【问题标题】:Why do condition variables sometimes erroneously wake up?为什么条件变量有时会错误地唤醒?
【发布时间】:2010-04-28 06:24:18
【问题描述】:

我早就知道你使用条件变量的方式是

lock
while not task_done
  wait on condition variable
unlock

因为有时条件变量会自发唤醒。但我一直不明白为什么会这样。过去我读过,制作一个没有这种行为的条件变量很昂贵,但仅此而已。

那么...为什么你需要担心在等待条件变量时被错误地唤醒?

【问题讨论】:

    标签: concurrency condition-variable


    【解决方案1】:

    不是条件变量会错误唤醒;条件变量只有在从另一个线程发出信号时才会唤醒。但是,有可能在线程被重新调度执行时,其他线程已经设法获取了您正在等待的资源,因此有必要仔细检查。例如,如果一组线程 x,y,z 正在等待 w 先前持有的某个资源 R,并且 x,y,z,w 通过条件变量进行通信......假设 w 与 R 完成并发出信号 x ,y,z。因此,x、y 和 z 将全部从等待队列中取出并放入运行队列中以安排执行。假设 x 首先被调度……那么它获取 R,然后它可能会进入睡眠状态,然后 y 可能会被调度,所以当 y 运行时,y 之前等待的资源 R 仍然不可用,所以 y 有必要再次入睡。然后z醒来,z也发现R还在使用,所以z需要再回去睡觉,等等

    如果您恰好有两个线程,并且条件变量仅在它们两个之间共享,则有时不执行该检查是可以的。但是,如果您想让您的应用程序动态化并且能够扩展到任意数量的线程,那么最好养成进行额外检查的习惯(更不用说更简单和更少担心),因为它需要大多数情况。

    【讨论】:

    • 不执行检查是绝对不行的。即使只有两个线程,也不能保证线程唤醒时条件为真。
    • @Nick,事实并非如此。如果条件是另一个线程已经释放了与条件变量关联的互斥锁(这样基本上你是在两个线程之间来回交替执行),那么它是安全的,因为你不能唤醒并重新获取锁,直到其他线程已发布它。当然,这并不是那么有用。
    • 我认为您试图强行提出不应该提出的观点。确实没有什么好的理由说明您不应该重新检查谓词。即使条件只与两个线程共享,也不能保证等待的线程不会被虚假唤醒。
    • @John,我并不是说不应该检查;相反,我已经说过总是检查是有意义的。但是,从技术上讲,在某些情况下检查是不必要的。
    • 我认为我们出于不同的原因存在分歧。我同意在正常情况下,如果您有两个共享共同条件的线程,那么您可以不重新检查而侥幸逃脱。但是,当可能发生虚假唤醒时,就没有不必要的情况了
    【解决方案2】:

    线程可以在没有信号的情况下唤醒。这称为虚假唤醒。然而,正是为什么它们发生是一个似乎陷入迷信和不确定性的问题。我看到的原因包括线程实现工作方式的副作用,或者被有意添加以强制程序员正确使用循环而不是 wait 周围的条件。

    【讨论】:

    • LOL - “被故意添加以强制程序员正确使用循环而不是等待的条件” - 哦等等,你在开玩笑吧? :-) 你不是!是苹果,不是吗?!!
    • @Bert F:实际上,我经常希望有一个 Linux 版本能够执行 POSIX 可以与程序结合的所有方式。套接字将从select 返回可读,然后没有可读取的内容。 write 将在 50% 的时间内返回部分结果。条件变量会自发唤醒。等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    相关资源
    最近更新 更多