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

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

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

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. 假设缓冲区已满,但消费者尚未启动。 所以(head = 0,tail = 0,sem_val = SIZE)。
  2. 从消费者线程调用dequeue()。 sem_wait()成功。 所以就在那个实例(head = 0,tail = 0,sem_val = SIZE-1)。 消费者开始阅读ar [0]。
  3. 现在有一个线程切换。 从生产者线程调用enqueue()。 sem_getvalue()将返回SIZE-1。 所以生产者在ar [0]写道。

基本上我认为你需要互斥保护来进行读写操作。 但添加互斥锁可能会阻塞线程。 所以我不确定你是否从这个逻辑得到预期的行为。