【问题标题】:Condition Variables and Unlocking Misconception [duplicate]条件变量和解锁误解
【发布时间】:2016-06-30 06:01:03
【问题描述】:

我注意到,在大多数条件变量示例中,我看到的内容如下:

pthread_cond_signal(&cond, &lock);
pthread_mutex_unlock(&lock);

我的问题是为什么要按这个顺序完成。为什么在释放锁之前先广播信号?如果在信号广播和解锁之间发生上下文切换,其他线程将从睡眠中唤醒并尝试访问有问题的锁,看到它仍然被锁定,然后回到待机状态,所以信号不会浪费了?

为什么这不是更好的解决方案:

pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond, &lock);

在这种情况下,锁在休眠的线程被唤醒之前被释放,因此它们实际上可以访问之前锁定的数据。

谁能帮我解决这个问题?

【问题讨论】:

  • @PaulGriffiths 该线程中与我的问题有关的答案指出“但这可能导致线程的最佳调度”,但没有详细说明原因。
  • icecrime 的答案链接到来自 David Butenhof 的电子邮件(诚然,此类信息在答案本身中会更好),其中详细说明了原因(以及有关为什么添加该警告性语言的一些历史细节符合标准)。结果是,除非您正在处理实时性能,否则在不锁定互斥锁的情况下发出信号或广播并没有太大问题。
  • 接受this question 的答案也可能会有所帮助。某些实现可能有一个互斥体等待队列,以避免您描述的那种多余的唤醒。
  • 如果你有一个糟糕的实现,会不必要地唤醒线程,那就使用更好的实现。体面的人应该知道,等待条件变量的线程在释放关联的互斥锁之前还没有准备好运行。如果实现无论如何都会唤醒线程,那么大概是有原因的。
  • 另外,您认为更好的解决方案显然更糟,因为它有两个昂贵的操作而不是一个。在持有关联互斥体的同时向条件变量发出信号基本上是免费的——它除了本地状态之外不会影响其他任何东西。但是,在释放锁时向条件变量发出信号需要同步,并且可能唤醒其他线程。

标签: c multithreading


【解决方案1】:

手册页有答案(强调我的):

无论线程当前是否拥有调用 pthread_cond_wait() 或 pthread_cond_timedwait() 的线程在等待期间与条件变量关联的互斥锁,线程都可以调用 pthread_cond_broadcast() 或 pthread_cond_signal() 函数;但是,如果需要可预测的调度行为,则该互斥锁应由调用 pthread_cond_broadcast() 或 pthread_cond_signal() 的线程锁定

【讨论】:

    【解决方案2】:

    我相信你可能会有所收获。

    这不是确定的,因为它来自 C++ 的 std::condition_variable,但我相信它在后台使用了 pthread_* 调用:http://en.cppreference.com/w/cpp/thread/condition_variable

    因此,在示例部分中,我们有:

    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
    

    【讨论】:

      猜你喜欢
      • 2020-09-13
      • 2021-09-29
      • 2013-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-17
      • 1970-01-01
      • 2010-11-06
      相关资源
      最近更新 更多