引用手册页:
使用条件变量时,总会有一个布尔谓词,涉及与每个条件等待关联的共享变量,如果线程应该继续,则为true。可能会发生pthread_cond_timedwait()或pthread_cond_wait()函数的虚假唤醒。由于从pthread_cond_timedwait()或pthread_cond_wait()返回并不意味着有关此谓词的值的任何内容,因此应在返回时重新评估谓词。
因此,即使您没有发信号,pthread_cond_wait
也可以返回。乍一看,这看起来非常残酷。它就像一个随机返回错误值或在实际到达正确的返回语句之前随机返回的函数。这似乎是一个主要的错误。但是他们选择在手册页中记录这一点而不是修复它的事实似乎表明,pthread_cond_wait
最终虚假地唤醒是有正当理由的。据推测,它有一些关于它是如何工作的固有的东西使得它无法帮助。问题是什么。
为什么 pthread_cond_wait
虚假地返回?为什么它不能保证它只是在它被正确发出信号后醒来?任何人都能解释其虚假行为的原因吗?
答案 0 :(得分:93)
至少有两件事'虚假唤醒'可能意味着:
pthread_cond_wait
中被阻止的线程可以从通话中返回,即使在此情况下没有呼叫信号或广播。pthread_cond_wait
中被阻止的线程返回,但是在重新获取互斥锁之后,发现基础谓词不再成立。但即使条件变量实现不允许前一种情况,也会发生后一种情况。考虑生产者消费者队列和三个线程。
pthread_cond_wait
,并在等待信号/广播的呼叫中阻塞。因此,您已经总是需要在循环下检查谓词,如果基础条件变量可以有其他类型的虚假唤醒,则没有区别。
答案 1 :(得分:74)
David R. Butenhof在"Programming with POSIX Threads"(第80页)中给出了以下解释:
虚假唤醒可能听起来很奇怪,但在某些多处理器系统上,使条件唤醒完全可预测可能会大大减慢所有条件变量操作。
在下面的comp.programming.threads discussion中,他扩展了设计背后的思想:
Patrick Doyle wrote: > In article , Tom Payne wrote: > >Kaz Kylheku wrote: > >: It is so because implementations can sometimes not avoid inserting > >: these spurious wakeups; it might be costly to prevent them. > >But why? Why is this so difficult? For example, are we talking about > >situations where a wait times out just as a signal arrives? > You know, I wonder if the designers of pthreads used logic like this: > users of condition variables have to check the condition on exit anyway, > so we will not be placing any additional burden on them if we allow > spurious wakeups; and since it is conceivable that allowing spurious > wakeups could make an implementation faster, it can only help if we > allow them. > They may not have had any particular implementation in mind. You're actually not far off at all, except you didn't push it far enough. The intent was to force correct/robust code by requiring predicate loops. This was driven by the provably correct academic contingent among the "core threadies" in the working group, though I don't think anyone really disagreed with the intent once they understood what it meant. We followed that intent with several levels of justification. The first was that "religiously" using a loop protects the application against its own imperfect coding practices. The second was that it wasn't difficult to abstractly imagine machines and implementation code that could exploit this requirement to improve the performance of average condition wait operations through optimizing the synchronization mechanisms. /------------------[ David.Buten...@compaq.com ]------------------\ | Compaq Computer Corporation POSIX Thread Architect | | My book: http://www.awl.com/cseng/titles/0-201-63392-2/ | \-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/
答案 2 :(得分:7)
pthread_cond_signal中的“条件信号多次唤醒”部分有一个pthread_cond_wait和pthread_cond_signal的示例实现,它涉及虚假唤醒。
答案 3 :(得分:3)
虽然我认为在设计时并未考虑过,但这是一个实际的技术原因:与线程取消结合使用时,在某些情况下,绝对有必要选择“虚假唤醒”选项,至少除非您愿意对可能的实施策略施加非常严格的约束。
关键问题在于,如果一个线程在pthread_cond_wait
中被阻塞时执行取消操作,那么副作用就好像它没有消耗条件变量上的任何信号一样。但是,要确保您在开始执行消除操作时尚未消耗信号就非常困难(且高度约束),并且在此阶段可能无法将信号“重新发布”到条件变量,因为您可能处于pthread_cond_signal
的调用者已经被证明销毁了condvar并释放了它所驻留的内存的情况下。
虚假唤醒的余量让您轻松自在。如果您可能已经消耗了一个信号(或者无论如何都想变得懒惰),则可以声明一个虚假的唤醒,而不是在条件变量阻止时继续执行取消操作,而不必声明取消操作,并成功返回。这完全不会干扰取消操作,因为正确的调用者将在下一次循环并再次调用pthread_cond_wait
时对未决的取消操作。