【问题标题】:why does producer consumer queue with single producer/consumer doesn't need mutex?为什么具有单个生产者/消费者的生产者消费者队列不需要互斥锁?
【发布时间】:2019-05-18 22:59:59
【问题描述】:

一个生产者和一个消费者的生产者消费者队列的代码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);
    }
}

我的问题是,为什么在单生产者单消费者情况下不需要互斥锁?

考虑以下几点:

  1. 队列中有 5 个项目,允许 10 个项目。
  2. 生产者产生一个项目,减少空信号量(并成功),然后开始将项目放入缓冲区,但未完成
  3. 消费者减少填充信号量,然后开始从缓冲区中删除项目
  4. 出乎意料。尝试从缓冲区 (3) 中删除项目,同时将项目放入缓冲区 (2)

为什么我描述的没有发生?

【问题讨论】:

    标签: parallel-processing synchronization mutex semaphore producer-consumer


    【解决方案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;
    }
    

    consumerPtrproducerPtr 只能在队列满或空时相等,在这种情况下,这些函数将不会被调用,因为执行进程将在信号量上保持阻塞。

    你可以说信号量被用作一种消息传递机制,允许对方增加它的指针,同步这个。

    现在,如果您在一侧有多个进程,则该侧将需要以原子方式执行增量和数据复制,因此需要互斥锁,但仅适用于具有多个进程的一侧,例如对于多生产者和多消费者队列,您可以使用 2 个单独的互斥锁来减少争用。

    【讨论】:

      猜你喜欢
      • 2014-03-26
      • 1970-01-01
      • 2015-09-25
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多