以下伪代码来自Wiki - producer-consumer problem。
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);
}
}
我的问题是,为什么我们可以在没有同步的情况下同时调用putItemIntoBuffer
和removeItemFromBuffer
?为什么这里没有竞争条件?
答案 0 :(得分:0)
简短的回答:它是一个伪代码,所以不要字面意思。代码的目的是展示如何同步消费者和生产者,而不是数据访问,就像开头的Wiki文章所述:
问题是确保生产者不会尝试将数据添加到缓冲区(如果已满)并且消费者不会尝试从空缓冲区中删除数据。
您要引用的伪代码使用信号量来解决此问题:
信号量解决了唤醒呼叫丢失的问题。
如果缓冲区大小为1,代码可能会正常工作而不会有任何额外的麻烦。但是任何缓冲区大小的putItemIntoBuffer()/ removeItemFromBuffer()的实际实现可能在内部使用锁来访问共享缓冲区,或者可以实现为无锁循环队列,就像下面显示的producer()/ consumer()函数之一一样。这篇文章,即:
volatile unsigned int produceCount = 0, consumeCount = 0;
ItemType buffer[BUFFER_SIZE];
void putItemIntoBuffer(ItemType *item) {
buffer[produceCount % BUFFER_SIZE] = *item;
++produceCount;
}
void removeItemFromBuffer(ItemType *item) {
*item = buffer[consumeCount % BUFFER_SIZE];
++consumeCount;
}
可能存在访问共享缓冲区的竞争条件,但它不是生产者 - 消费者问题的主要点,因此不是所提及的Wiki文章的主要观点。