【问题标题】:How does pthread_cond_wait (conditon variable) unblock all threads only once, not multiple times?pthread_cond_wait(条件变量)如何只取消阻塞所有线程一次,而不是多次?
【发布时间】:2019-07-01 02:19:41
【问题描述】:

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

生产者线程使用 pthread_cond_broadcast 广播条件。并且工作线程被 pthread_cond_wait 阻塞。

代码看起来像这样:

线程 1(生产者线程):

pthread_mutex_lock
pthread_cond_broadcast
pthread_mutex_unlock

线程 2(工作者/消费者线程):

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

  // Thread operation
  work = 0;
  pthread_mutex_unlock
}

线程 3(工作者/消费者线程):

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,但没有得到任何线索。

任何关于我缺乏或想法错误的帮助或建议,我们将不胜感激。

谢谢

【问题讨论】:

    标签: c linux multithreading pthreads conditional-statements


    【解决方案1】:

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

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

    换句话说,当线程 1 广播条件时,让 说线程2首先在条件上解除阻塞,执行线程 操作并调用thread_cond_wait并阻塞自身。

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

    此时,两个线程都被阻塞等待 条件,那么条件变量是否重置?

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

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

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

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

    如果是这样,它是怎么做的 知道什么时候重置,而不是 2 个工作线程,我可以有 5 个 工作线程?

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

    为什么线程 2 和线程 3 不再次解除阻塞 一样的条件?

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

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

    【讨论】:

      猜你喜欢
      • 2021-10-12
      • 2022-11-23
      • 1970-01-01
      • 2013-05-14
      • 2021-09-06
      • 1970-01-01
      • 2021-11-20
      • 2016-09-07
      • 1970-01-01
      相关资源
      最近更新 更多