具有单个生产者和单个消费者的生产者消费者队列的代码From wikipedia为:
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(item);
和removeItemFromBuffer();
部分:
mutex buffer_mutex; // similar to "semaphore buffer_mutex = 1", but different (see notes below)
semaphore fillCount = 0;
semaphore emptyCount = BUFFER_SIZE;
procedure producer()
{
while (true)
{
item = produceItem();
down(emptyCount);
down(buffer_mutex);
putItemIntoBuffer(item);
up(buffer_mutex);
up(fillCount);
}
}
procedure consumer()
{
while (true)
{
down(fillCount);
down(buffer_mutex);
item = removeItemFromBuffer();
up(buffer_mutex);
up(emptyCount);
consumeItem(item);
}
}
我的问题是,为什么单一生产者单一消费者情况下不需要互斥体?
请考虑以下内容:
为什么我的描述没有发生?
答案 0 :(得分:1)
因为这样的队列通常将实现为循环队列。生产者将写在队列的尾部,而消费者则从头读。他们永远不会同时访问相同的内存。
这里的想法是消费者和生产者都可以独立跟踪尾巴/头部的位置。
考虑以下伪代码:
T data[BUFFER_SIZE];
int producerPtr = 0, consumerPtr = 0;
void putItemIntoBuffer(Item item)
{
data[producerPtr] = item;
producerPtr = (producerPtr + 1) % BUFFER_SIZE;
}
Item removeItemFromBuffer(void)
{
Item item = data[consumerPtr ];
consumerPtr = (consumerPtr + 1) % BUFFER_SIZE;
return item;
}
consumerPtr
和producerPtr
只能在队列已满或为空时相等,在这种情况下,这些函数将不会被调用,因为执行过程将一直保持在信号量上。
您可以说信号量被用作消息传递机制,从而允许另一端增加其指针,使其同步。
现在,如果您在一侧有多个进程,则该侧将需要原子执行增量和数据复制,因此需要互斥体,但仅对于具有多个进程的那一侧(例如,对于多生产者和多消费者队列,您可以使用2个独立的互斥锁来减少争用。