睡眠与唤醒

2024年8月28日 | 阅读 4 分钟

(生产者-消费者问题)

让我们来研究一下睡眠和唤醒的基本模型。假设我们有两个系统调用,分别是 sleepwake。调用 sleep 的进程将被阻塞,而调用 wake 的进程将被唤醒。

有一个著名的例子叫做生产者-消费者问题,这是模拟睡眠和唤醒机制最受欢迎的问题。

睡眠和唤醒的概念非常简单。如果临界区不为空,则进程将进入睡眠状态。它将被当前正在临界区内执行的另一个进程唤醒,以便该进程可以进入临界区。

在生产者-消费者问题中,假设有两个进程,一个进程写入数据,另一个进程读取数据。写入数据的进程称为生产者,而读取数据的进程称为消费者

为了读写,它们都使用一个缓冲区。下面显示了模拟睡眠和唤醒机制以解决生产者-消费者问题的代码。



生产者生产物品并将其插入缓冲区。全局变量 count 的值在每次插入时都会增加。如果缓冲区完全填满,没有可用插槽,则生产者将休眠,否则它会继续插入。

在消费者端,count 的值在每次消费时都会减 1。如果在任何时候缓冲区为空,则消费者将休眠,否则,它会继续消费物品并将 count 的值减 1。

如果缓冲区中至少有 1 个待消费的物品,生产者将唤醒消费者。如果缓冲区中至少有一个可用插槽,以便生产者可以写入,消费者将唤醒生产者。

然而,问题出现在消费者即将进入睡眠状态之前被抢占的情况下。现在消费者既没有睡眠也没有消费。由于生产者不知道消费者实际上没有睡眠,因此它会不断唤醒消费者,而消费者由于没有睡眠而没有响应。

这导致系统调用的浪费。当消费者再次被调度时,它将进入睡眠状态,因为它在被抢占时即将睡眠。

生产者不断向缓冲区写入数据,一段时间后缓冲区被填满。生产者也会在那时休眠,记住当缓冲区中有可用插槽时,消费者会唤醒它。

消费者也在睡眠,并且不知道生产者会唤醒它。

这是一种死锁,生产者和消费者都处于非活动状态,并等待对方唤醒它们。这是一个需要解决的严重问题。

使用标志位解决此问题

可以使用一个标志位来解决这个问题。生产者在第一次调用唤醒时可以设置该位。当消费者被调度时,它会检查该位。

消费者现在将知道生产者试图唤醒它,因此它不会睡眠并进入就绪状态,以消费生产者生产的任何东西。

此解决方案仅适用于一对生产者和消费者,如果有 n 个生产者和 n 个消费者怎么办?在这种情况下,需要维护一个整数,它可以记录已进行了多少次唤醒调用,以及有多少消费者不需要睡眠。这个整数变量称为信号量。我们稍后将详细讨论信号量。


下一个主题信号量介绍