生产者消费者问题,为啥不能用一个信号量实现同步( 二 )


你要在仓库堆东西。在去仓库之前先告诉其他人,仓库这块地我占了,你们别用。确保了我能放进去。真正放完之后再去告诉客户,你可以过来取了。 (反之同理)
如果只有一个inventory变量,那这两个操作就合二为一了。如果一开始就既占了位置也告诉客户可以取。那可能你还没放客户就来取了。如果你决定放完再通知,那你也不知道有没有空位可以放。
写的比较乱,见谅!

■网友
首先,生产者消费者需要2个同步信号量,1个互斥信号量。互斥就不说了,问题就是为什么2个同步(full+empty)和1个同步(full或者empty)。empty代表空闲缓冲区的数量,full代表产品的数量。
首先,假设只有一个同步信号量empty=5,也就是缓冲区有5个空位;
生产者每次生产就申请一个空位,即p(empty)。
假设5次生产之后,满了,临界区满了=生产者不生产了,现在生产者被阻塞,cpu切换到消费者;
消费者在每次消费成功后,执行v(buffer),但是在消费前并没有受到任何制约!这时候的效果就是,消费者可以无限消费,然后empty的值会无限增加,消费者已经消费了刚才生产的5个产品之后都还可以继续消费。
如果还不明白,假设现在有另一个同步信号量full=0,也就是,缓冲区有0个产品,但是不知道缓冲区有多大的限制。现在每次生产都在生产之后执行v(full),也就是full++,然而full可以一直增加,因为没有上限,也就是消费者被制约但是生产者没被制约。
综上,2个信号量,一个限制生产者,一个限制消费者;1个信号量无法同事限制他们2个。
如果还不明白,不要管互斥量,把仅有1个信号量的情况写出来,然后多分析几次。其实我最先也是觉得1个就够了,然后发现很多情况不满足,不得不的加入第二个信号量。
最后还要注意,生产者不只是生产产品,还要把产品放入临界区,这是2个不同,互不相干的操作;而消费者也是要执行取出产品和使用产品2个操作。

■网友
赞成陈词同学对生产者消费者模型的信号分析。
场景分析:
1. 生产者和消费者的互斥访问
2. 缓冲区满制约生产者,缓冲区空制约消费者
这里针对您写的第一个生产者消费者模型问题很明显,您试图通过一个互斥量来控制线程互斥(可行)和一个信号量(不可行)完成生产者和消费者在有缓冲区长度的情况下同步这显然是不可能的,根据场景2的表述生产者在消费者阻塞的时候需要唤醒它,消费者在生产者阻塞的时候也需要唤醒它,一个信号量只能阻塞消费者(消费者可以将信号量减到0),并不能控制生产者。所以可以得出这里的关系是需要由生产者控制 可以消费多少 由消费者控制 可以生产多少 ,可以消费多少和可以生产多少是两个不同的资源,所以需要用两个信号量去访问。

■网友
n = 10mutex = 1producer:P(mutex)V(n)produce() // 假如此处这里是生产 (题主忘了写)V(mutex)cosumer:P(mutex)P(n)consume() // 假如此处这里是消费 (题主忘了写)V(mutex)上面是你的代码
假如消费者先执行的情况, 我模拟一下你消费者的代码:
P(mutex) √ 成立, 没问题!
P(n) √ 成立, 没问题.
consume() // √ 成立, 问题大了.
执行这句必定会出错, 为什么?
因为你的缓冲区是空的, 但是消费者却直接执行了.

错误的原因:消费者生产者--不仅仅有个互斥锁(保证资源互斥使用), 还要有个同步锁(要保证生产者生产的动作, 消费者后执行消费的动作). 所以至少要有两个信号量.
【生产者消费者问题,为啥不能用一个信号量实现同步】 代码中的一对互斥锁: P(mutex), V(mutex) , 一对同步锁: P(empty), V(mutex)

另一个错误:
你贴的另一个关于两个信号量的伪码, 也是错误的.


推荐阅读