单个生产者/消费者循环缓冲区,仅阻止消费者

时间:2016-11-23 05:58:46

标签: c multithreading pthreads semaphore

我想用单个生产者和单个消费者实现缓冲区,其中只有消费者可能被阻止。这里重要的细节是,如果队列已满,生产者可以删除更新。

我考虑过转换一个无等待的实现,但乍一看似乎没有简单的方法来通知消费者新数据已经到达而不会丢失通知。所以我采用了一种非常简单的方法,使用计数信号量(为清楚起见省略了一些错误处理细节):

Object ar[SIZE];
int head = 0, tail = 0;
sem_t semItems; // initialized to 0

void enqueue(Object o) {
    int val;
    sem_getvalue(&semItems, &val);
    if (val < SIZE - 1) {
        ar[head] = o;
        head = (head + 1) % SIZE;
        sem_post(&semItems);
    }
    else {
       // dropped
    }
}
Object dequeue(void) {
    sem_wait(&semItems);
    Object o = ar[tail];
    tail = (tail + 1) % SIZE;
    return o;
}

此代码是否存在安全问题?我很惊讶没有在流行文献中看到任何类似的实现。另一个问题是sem_post()是否会阻塞(在linux下调用futex_wake())。当然也欢迎更简单的解决方案。

编辑:编辑的代码在读者和作者之间留一个空格(参见Mayurk的回复)。

1 个答案:

答案 0 :(得分:2)

我可以在此实现中看到一个问题。请考虑以下顺序。

  1. 假设缓冲区已满,但消费者尚未启动。所以(head = 0,tail = 0,sem_val = SIZE)。
  2. 从消费者线程调用
  3. dequeue()。 sem_wait()成功。所以就在那个例子(head = 0,tail = 0,sem_val = SIZE-1)。消费者开始阅读ar [0]。
  4. 现在有一个线程切换。从生产者线程调用enqueue()。 sem_getvalue()将返回SIZE-1。生产者在ar [0]写道。
  5. 基本上我认为你需要互斥保护来进行读写操作。但添加互斥锁可能会阻塞线程。所以我不确定你是否从这个逻辑中获得预期的行为。