生产者使用者同步,仅使用 1 个信号量



在生产者-消费者问题中,标准解决方案使用 3 个信号量。
但是,我想知道我们是否可以只使用 1 个信号量:

semaphore mutex = 1
procedure producer() {
while (true) {
down(mutex)
if (bufferNotFull()) {
item = produceItem()
putItemIntoBuffer(item)
}
up(mutex)
}
}
procedure consumer() {
while (true) {
down(mutex)
if (bufferNotEmpty()) {
item = removeItemFromBuffer()
consumeItem(item)
}
up(mutex)
}
}

这个解决方案和标准解决方案一样好吗?

供参考的标准解决方案:

semaphore mutex = 1
semaphore fillCount = 0
semaphore emptyCount = BUFFER_SIZE
procedure producer() {
while (true) {
item = produceItem()
down(emptyCount)
down(mutex)
putItemIntoBuffer(item)
up(mutex)
up(fillCount)
}
}
procedure consumer() {
while (true) {
down(fillCount)
down(mutex)
item = removeItemFromBuffer()
consumeItem(item)
up(mutex)
up(emptyCount)
}
}

"标准解决方案"不必使用 3 个信号量。即使是你链接的维基百科文章,对于只有一个生产者和一个消费者的情况,也有一个双信号量解决方案:

semaphore fillCount = 0; // items produced
semaphore emptyCount = BUFFER_SIZE; // remaining space
procedure producer() 
{
while (true) 
{
item = produceItem();
down(emptyCount);
putItemIntoBuffer(item);
up(fillCount);
}
}
procedure consumer() 
{
while (true) 
{
down(fillCount);
item = removeItemFromBuffer();
up(emptyCount);
consumeItem(item);
}
}

具有单个信号量的解决方案不是很好,因为它们在您实际想要时只为您提供一个等待条件 - "等待可用空间"和"等待项目"。不能同时使用单个信号量来执行这两项操作。

无论如何,您的解决方案没有错,它只是效率非常低,因为在任何给定时刻,只有一个生产者或单个消费者可以运行。这本质上是单线程代码,仅在线程之间具有锁和上下文切换。因此,它的效率甚至低于实际的单线程代码。

还有一件事 - 物品生产和消费通常不是关键部分的一部分。在使用或生产项目时,另一个线程可以运行。我们只需要在使用缓冲区时相互排斥。

最新更新