pthread_mutex_wait多个生产者和消费者

时间:2015-01-28 07:06:44

标签: c++ multithreading pthreads posix producer-consumer

我正在浏览thisthis链接。基本上,他们正在讨论为什么经典的单线程生产者消费者设计(signalwait不适用于多生产者场景)。我怀疑一直困扰着我 -

作者论证
考虑参考代码

char queue[MAX];  //global
int head = 0, tail = 0; //global
struct cv not_full, not_empty;
struct lock qlock;

void produce(char data) {
  acquire(&qlock);
  if ((head + 1) % MAX  ==  tail) {
    wait(&not_full, &qlock);   //line 1
  }
  queue[head] = data; //line 2
  head = (head + 1) % MAX;
  notify(&not_full);
  release(&qlock);
}

char consume(void) {
  acquire(&qlock);
  if (tail == head) {
    wait(&not_empty, &qlock);
  }
  e = queue[tail];
  tail = (tail + 1) % MAX;
  notify(&not_empty);
  release(&qlock);
  return e;
}

在上面的代码中,如果有两个生产者,line 1将在单个使用者的生产者线程中woken up(当队列未满时)。因此两个生产者都可以添加到队列中,导致队列溢出。

我怀疑
一个。我们使用互斥锁来保护队列。因此,即使wait在多个生产者线程中被唤醒,只有一个生产者仍然具有互斥锁 - 所以逻辑上只有一个生产者拥有'添加到队列的权限。因为当我们离开wait时,我们会获得互斥量。

CAVET
我使用POSIX互斥,cond var作为参考。但是,我没有看到用POSIX编写的文章作为参考标准。

问题
我对wait具体pthread_cond_wait的理解是否正确?对于多个生产者,代码的完整性仍然保持不变。

1 个答案:

答案 0 :(得分:1)

作者在其文章末尾提到 wait()和notify()的语义

  

notify(cv)唤醒当前在该cv上等待的 所有 线程

因此,您对等待的理解不正确,notify在posix中应为pthread_cond_broadcast

此外documentation of pthread_cond_signal规定了

  

pthread_cond_signal()调用取消阻止 至少一个 的主题   在指定的条件变量cond上被阻塞(如果有的话)   cond上的线程被阻止。

这与您的“只有一个制作人”假设有所不同。

正如作者所示,上述代码的完整性并未由多个生产者维护。

修改

pseudocode of a condition variable wait可能看起来像

void wait (condition *cv, mutex *mx) 
{
    mutex_acquire(&c->listLock);  /* protect the queue */
    enqueue (&c->next, &c->prev, thr_self()); /* enqueue */
    mutex_release (&c->listLock); /* we're done with the list */

    /* The suspend and release_mutex() operation should be atomic */
    release_mutex (mx));
    thr_suspend (self);  /* Sleep 'til someone wakes us */

    <-------- notify executes somewhere else

    mutex_acquire (mx); /* Woke up -- our turn, get resource lock */
    return;
}

signal期间,suspend状态中队列中的至少一个线程被唤醒。但pthread并不能保证 只有一个 。现在它们可以运行了。但他们仍然需要获得锁定以确保彼此之间相互排斥。

因此,当第一个发布互斥锁时,第二个发布互斥锁,依此类推。

这意味着唤醒生产者将一个接一个地执行

queue[head] = data; //line 2
head = (head + 1) % MAX;
notify(&not_full);
release(&qlock);