当只有一个生产者和一个消费者时,为什么不需要同步缓冲区?

时间:2017-11-05 17:33:53

标签: multithreading operating-system semaphore race-condition producer-consumer

以下伪代码来自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);
    }
}

我的问题是,为什么我们可以在没有同步的情况下同时调用putItemIntoBufferremoveItemFromBuffer?为什么这里没有竞争条件?

1 个答案:

答案 0 :(得分:0)

为什么我们可以在没有同步的情况下同时调用putItemIntoBuffer和removeItemFromBuffer?

简短的回答:它是一个伪代码,所以不要字面意思。代码的目的是展示如何同步消费者和生产者,而不是数据访问,就像开头的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文章的主要观点。