生产者消费者问题

Posted by JimWang on 2021-02-06

生产者消费者问题

image-20210206153202837

对于缓冲区而言是互斥的,同一时刻只能由一个进程完成生产或消费(缓冲区是临界资源,各进程必须互斥的访问)
生产者、消费者共享一个初始为空、大小为n的缓冲区。
只有缓冲区没满时,生产者才能把产品放进缓冲区,否则必须等待。
只有缓冲区不空时,消费者才能从中取出产品,否则等待。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
semaphore mutex = 1;  // 互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n; // 同步信号量,表示空闲缓冲区的数量
semaphore full = 0; // 同步信号量,表示产品的数量,即非空缓冲区的数量

void producer() {
while (1) {
/*生产一个产品*/
P(empty); // 消耗一个空闲缓冲区。这里是先判断了商品是否已满,如果不满,就能消耗一个缓冲区,否则就阻塞着,等商品被消耗了再来增加产品。

P(mutex); // 对缓冲区上锁。 互斥锁,避免同时的生产和消耗,导致数字出问题
/*把产品放入缓冲区*/
V(mutex); // 对缓冲区解锁

V(full); // 增加一个产品
}
}

void consumer() {
while (1) {
P(full); // 消耗一个产品

P(mutex); // 对缓冲区上锁
/*从缓冲区取出一个产品*/
V(mutex); // 对缓冲区解锁

V(empty); // 增加一个空闲缓冲区
/*使用产品*/
}
}

注意:顺序不能颠倒

  1. P(empty); V(empty);是实现消费产品之后,对空闲缓冲区的数目实现进程的同步,因此在消费者最后执行V操作,在生产者最前面进行P操作。
  2. P(full); V(full);是实现生产产品之后,对产品的的数目的实现进程同步,因此在生产者最后执行V操作,在消费者最前面进行P操作。
  3. P(mutex);V(mutex);实现对缓冲区临界资源的互斥访问。

问题

这里如果交换了两个P的位置,那么可能先拿到了互斥锁,此时发现商品满的,不需要上商品,阻塞了,但是互斥锁还在手里。消费者就没法消费了,那么就死锁了,永远没人来消费。

如果交换两个V的位置,不会死锁,但是锁的粒度增大,会导致运行效率低。