增强线程中的虚假解除阻塞

时间:2009-03-09 08:08:02

标签: multithreading boost wait conditional-statements

我今天在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()如果函数退出   例外。

所以我感兴趣的是“虚假”这个词的含义。为什么线程会因为虚假原因而被解除阻塞?可以做些什么来解决这个问题?

2 个答案:

答案 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一样的概念,顺便说一下,不限于提升)也可能会让你感兴趣。