【问题标题】:Spurious unblocking in boost threadboost线程中的虚假解除阻塞
【发布时间】:2010-10-12 03:20:42
【问题描述】:

我今天在Boost thread documentation 看到了这个有趣的段落:

void wait(boost::unique_lock<boost::mutex>& lock)

...

效果:原子调用 lock.unlock() 并阻塞当前线程。这 线程将在收到通知时解除阻塞 调用 this->notify_one() 或 this->notify_all(),或虚假地。 当线程被解除阻塞时(对于 不管什么原因),锁是 通过调用 lock.lock() 重新获取 在调用等待返回之前。这 锁也通过调用重新获取 lock.lock() 如果函数退出 一个例外。

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

【问题讨论】:

    标签: multithreading boost wait conditional-statements


    【解决方案1】:

    This article by Anthony Williams特别详细。

    无法预测虚假尾流: 它们基本上是随机的 用户的观点。然而,他们 线程库时常出现 不能可靠地确保等待 线程不会错过通知。 由于错过的通知会 使条件变量无用, 线程库唤醒线程 从它的等待而不是采取 风险。

    他还指出,您不应该使用需要持续时间的timed_wait 重载,您通常应该使用带有谓词的版本

    这是初学者的错误,还有一个 这很容易用一个简单的方法克服 规则:总是检查你的谓词 等待条件时循环 多变的。更阴险的错误来了 来自 timed_wait()。

    This article by Vladimir Prus也很有趣。

    但是为什么我们需要while循环, 我们不能写吗:

    if (!something_happened)
      c.wait(m);
    

    我们不能。杀手的原因是'等待'可以 返回没有任何“通知”电话。 这就是所谓的虚假唤醒,是 POSIX 明确允许。 本质上,仅从“等待”返回 表示共享数据可能 已更改,因此数据必须是 再次评估。

    好的,那为什么还没有解决呢? 第一个原因是没有人想要 要解决这个问题。包装呼叫“等待” 几个人非常需要一个循环 其他原因。但这些原因 需要解释,虽然是虚假的 唤醒是可以应用的锤子 任何一年级学生没有 失败。

    【讨论】:

    • 看起来我们一直在寻找相同的页面,这并不完全出乎意料:)
    • 是的,这是我今天研究的总结,当时我找出了我所遭受的可怕错误的原因。在这一点上,boost 文档可能会更清楚
    • 我发现 boosts 整个系统等待和通知——尤其是在 boost::interprocess 中——非常令人沮丧。我只会在您需要它跨平台并立即完成时使用它。
    【解决方案2】:

    This blog post 给出了 Linux 的原因,即当信号传递给进程时返回的futex 系统调用。不幸的是,它没有解释任何其他内容(实际上是在要求更多信息)。

    Wikipedia entry on spurious wakeups(这似乎是一个 posix 范围的概念,顺便说一句,不限于 boost)您可能也会感兴趣。

    【讨论】:

    • 嗯,是的,这并不是一个真正令人满意的答案,因为它只适用于一个平台,尽管我想如果让它在 Linux 上“正确”工作真的非常困难,那么可能是记录虚假唤醒的正当理由
    猜你喜欢
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-12
    • 2021-09-06
    • 1970-01-01
    相关资源
    最近更新 更多