pthread_cond_wait(条件变量)如何只解锁所有线程一次,而不是多次?

How does pthread_cond_wait (conditon variable) unblock all threads only once, not multiple times?

我已经成功实现了一个生产者线程和 2 个工作线程或消费者线程。

生产者线程使用pthread_cond_broadcast广播条件。工作线程被 pthread_cond_wait.

阻塞

代码看起来像这样:

线程 1(生产者线程):

pthread_mutex_lock
pthread_cond_broadcast
pthread_mutex_unlock

线程 2(Worker/Consumer 线程):

work = 1
while(1)
{
  pthread_mutex_lock
  while(!work)
  {
    work = 1;
    pthread_cond_wait
  }

  // Thread operation
  work = 0;
  pthread_mutex_unlock
}

线程 3(Worker/Consumer 线程):

work = 1
while(1)
{
  pthread_mutex_lock
  while(!work)
  {
    work = 1;
    pthread_cond_wait
  }

  // Thread operation
  work = 0;
  pthread_mutex_unlock
}

我的问题是为什么线程 2 或线程 3 不重新执行自身?

换句话说,当条件被线程 1 广播时,假设线程 2 首先解除对条件的阻塞,执行线程操作并调用 thread_cond_wait 并阻塞自己。

现在线程 3 根据条件解除阻塞,执行线程操作并调用 thread_cond_wait 并阻塞自身。

此时两个线程都阻塞等待条件,那么条件变量是不是重置了?如果是这样,它怎么知道什么时候重置,而不是 2 个工作线程,我可以有 5 个工作线程?

为什么线程 2 和线程 3 不在相同条件下再次解除阻塞?

我想知道内部机制,关于线程如何针对特定条件只解除阻塞一次,直到发送新的广播才解除阻塞。

我曾尝试阅读相关内容,但我只能看到,如果发送条件广播,则所有等待该条件的线程都将畅通无阻。我不明白的是为什么同一个线程不会多次解除对同一个条件的阻塞?

我已经尝试查看 pthread_cond_t,但没有得到任何线索。

对于我的不足或想法错误的任何帮助或建议,将不胜感激。

谢谢

My question is why does Thread 2 or Thread 3 does not re-execute itself ?

因为条件变量不是这样工作的。

In other words, when the condition was broadcasted by Thread 1, lets say Thread 2 unblocks on the condition first, performs thread operation and calls thread_cond_wait and blocks itself.

Now Thread 3 unblocks on the condition, performs thread operation and calls thread_cond_wait and block itself.

At this point of time, both the threads are blocked waiting for the condition, so is the condition variable reset ?

这个问题表明由条件变量表示的状态模型很差,因为答案是肯定的和否定的。实现细节可能有很大差异,但理论上,CV 管理的主要状态由 "wait set" 当前等待 CV 的线程组成。这些线程无法继续,它们在 CV 上被阻止。

可以对简历执行三种主要操作:

  • 线程可以通过对其执行 "wait" 操作将自己添加到 CV 的等待集中,从而导致自己在 CV 上阻塞。
  • 一个线程可以通过对其执行 "notify" 操作来导致由 CV 选择的另一个线程从 CV 的等待集中(如果非空)删除。就 CV 而言,两个线程都有资格继续进行。
  • 线程可以通过对其执行 "broadcast" 操作来清空 CV 的等待集。

CV 不携带指示它们是否已收到信号的持久状态。他们只知道他们的等待集和(在 pthreads 的实现中)一个互斥量,从等待集中删除的线程必须先获取该互斥量才能 return 从等待操作中进行。无需重置 CV 来准备接受更多线程进入其等待集。

If so, how does it know when to reset, as instead of 2 worker threads, I could have 5 worker threads ?

它不重置,在任何意义上都与已经描述的操作不同。任何等待它的线程都会被添加到等待集中,并且只要它留在那里就没有资格被调度。 CV 上的任何信号和广播操作都会自动影响执行操作时的等待集。从等待集中移除的线程不再在 CV 上被阻塞,但它们可能会在获取关联的互斥体时被阻塞。

Why doesn't Thread 2 and Thread 3 unblock themselves again for the same condition ?

因为条件变量不是这样工作的。

线程 2 和 3 再次等待是 CV 支持的唯一一种重置。那些已被重新添加到等待集中的线程,没有理由认为它们会在对该 CV 执行(另一个)信号或广播操作之前继续进行。没有过去信号/广播的记忆,只有等待集的当前内容。