Concurrency 为什么条件变量有时会错误地唤醒?

Concurrency 为什么条件变量有时会错误地唤醒?,concurrency,condition-variable,Concurrency,Condition Variable,我早就知道使用条件变量的方式是 lock while not task_done wait on condition variable unlock 因为有时条件变量会自动唤醒。但我一直不明白为什么会这样。在过去我读到过,制作一个没有这种行为的条件变量是很昂贵的,但仅此而已 所以。。。为什么您需要担心在等待条件变量时被错误唤醒?不是条件变量会错误唤醒;条件变量只有在从另一个线程发出信号时才会唤醒。但是,当线程被重新安排执行时,其他线程可能已经设法占用了您正在等待的资源,因此有必要进行双重检

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

lock
while not task_done
  wait on condition variable
unlock
因为有时条件变量会自动唤醒。但我一直不明白为什么会这样。在过去我读到过,制作一个没有这种行为的条件变量是很昂贵的,但仅此而已


所以。。。为什么您需要担心在等待条件变量时被错误唤醒?

不是条件变量会错误唤醒;条件变量只有在从另一个线程发出信号时才会唤醒。但是,当线程被重新安排执行时,其他线程可能已经设法占用了您正在等待的资源,因此有必要进行双重检查。例如,如果一组线程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需要再次回到睡眠状态,等等


如果您正好有两个线程,并且条件变量仅在其中两个线程之间共享,则有时可以不执行该检查。然而,如果你想让你的应用程序具有动态性,并且能够扩展到任意数量的线程,那么最好养成这样的习惯(更不用说更简单、更不令人担忧),因为在大多数情况下都需要进行额外的检查。

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

周围的条件。不执行检查是不好的。即使只有两个线程,也不能保证当线程唤醒时该条件为真。@Nick,事实并非如此。如果条件是另一个线程已经释放了与条件变量相关联的互斥锁(因此实际上您在两个线程之间来回交替执行),那么它是安全的,因为在另一个线程释放锁之前,您无法唤醒并重新获取锁。当然,这没什么用。我想你是在试图强行提出一个不应该提出的观点。你真的没有理由不重新检查谓词。即使只有两个线程共享该条件,也不会有人指责正在等待的线程不会被错误唤醒。@John,我不是说不应该检查;相反,我已经说过,经常检查是有道理的。然而,准确地说,在某些情况下,检查是不必要的。我认为我们出于不同的原因不同意。我同意,在正常情况下,如果你有两个线程共享一个共同的条件,那么你可以不重新检查。但是当虚假的唤醒可能发生时,就没有不必要的情况了——“故意添加它以迫使程序员正确地使用循环而不是等待周围的条件”——哦,等等,你在开玩笑,对吧?:-)你不是!是苹果,不是吗@Bert F:事实上,我经常希望有一个版本的Linux,它能以POSIX可以处理程序的所有方式运行。套接字将从
select
返回可读,然后没有任何内容可读取<代码>写入将在50%的时间内返回部分结果。条件变量会自动唤醒。等