我今天在Boost thread documentation看到了这个有趣的段落:
void wait(boost::unique_lock<boost::mutex>& lock)
...
效果:原子调用lock.unlock() 并阻止当前线程。该 线程将在通知时解除阻止 请致电此&gt; notify_one()或 this-&gt; notify_all()或虚假。 线程解除阻塞时(for 无论什么原因),锁是 通过调用lock.lock()重新获取 在等待调用之前返回。该 也可以通过调用重新获取锁 lock.lock()如果函数退出 例外。
所以我感兴趣的是“虚假”这个词的含义。为什么线程会因为虚假原因而被解除阻塞?可以做些什么来解决这个问题?
答案 0 :(得分:11)
This article by Anthony Williams特别详细。
无法预测虚假的醒来: 他们基本上是随机的 用户的观点。但是,他们 通常在线程库时发生 不能可靠地保证一个等待 线程不会错过通知。 由于错过了通知 渲染条件变量无用, 线程库唤醒线程 从等待而不是采取 风险。
他还指出,您不应该使用持续时间较长的timed_wait
重载,并且通常应该使用带谓词的版本
这是初学者的错误,还有一个 这很容易通过简单的方法克服 规则:总是检查你的谓词 等待条件时循环 变量。更阴险的错误来了 来自timed_wait()。
This article by Vladimir Prus也很有趣。
但为什么我们需要while循环, 我们不能写:
if (!something_happened)
c.wait(m);
我们做不到。而杀手的原因是'等待'可以 没有任何'通知'电话返回。 那被称为虚假唤醒而且是 POSIX明确允许。 基本上,只从“等待”返回 表示共享数据可能 已经改变了,所以必须有数据 再次评估。
好的,为什么这还没有修好呢? 第一个原因是没有人想要 要解决这个问题。打电话给“等待” 一些循环非常需要几个 其他原因。但那些原因 需要解释,而虚假 唤醒是一种可以应用的锤子 没有的任何一年级学生 失败。
答案 1 :(得分:2)
This blog post给出了Linux的原因,就信号传递给进程时返回的futex
系统调用而言。不幸的是,它没有解释任何其他事情(实际上是要求更多信息)。
Wikipedia entry on spurious wakeups(看起来像posix一样的概念,顺便说一下,不限于提升)也可能会让你感兴趣。