【问题标题】:how to avoid spurious wakeup without a predicate?如何避免没有谓词的虚假唤醒?
【发布时间】:2021-11-29 13:03:04
【问题描述】:

我有一个线程,我们称之为 t1,它会在 x 秒后定期发送一些东西。 这个“x 秒部分”可以从其他线程 (t2) 更改。 我应该能够从线程 t1 执行以下操作。

  1. 等待“x 秒”,然后发送内容
  2. 如果线程 t2 发送另一个 "x" 值,则不要发送,而是转到步骤 1。

我已经通过 wait_for() 使用了条件变量

我只想在“x 秒”结束时发送。

目前我已经在没有谓词的情况下实现了它(因为我不需要它)是这样的:

auto done = wait_for(lock,x seconds);

if(done == cv_status::timeout) 
{
/*perform send operation*/
}

但有时我会在 timeout 之前看到“发送发生”,我认为这是由于虚假唤醒和缺少谓词造成的。

我的问题是如何在没有谓词的情况下处理虚假唤醒?我应该为此采取另一种方法吗? 我不需要谓词,因为线程 t1 在特定条件下休眠(当 x 为 0 时),我希望它(t1)在没有任何条件的情况下被 t2 唤醒。

这是我第一个使用 cond 变量的任务,我还在学习 CPP,提前谢谢你。

【问题讨论】:

标签: c++ multithreading condition-variable spurious-wakeup


【解决方案1】:

不,没有谓词就无法避免虚假唤醒。首先,这就是谓词的用途。 C++ 标准明确允许等待偶尔出现虚假唤醒,但没有办法阻止它们。

您唯一的选择是:

  1. 使用谓词

  2. 不要使用谓词,但要考虑到您可能会对整体逻辑进行虚假唤醒。您无法防止虚假唤醒,因此请调整程序的逻辑以适应它们。

例如:在这种情况下,您的目标是等待一段时间。所以,在等待之前,看看std::chrono::steady_clock::now() 说了什么,并计算在给定时间段过去后它应该说什么。然后在您据称等待规定的时间后再次检查。如果仍然小于预期的超时时间,请计算剩余的时间,然后再次等待,希望下次运气更好。起泡、冲洗、重复。

在所有情况下,请记住,即使没有虚假唤醒,您也几乎无法保证。即使您要求在整整 5 秒后被唤醒,wait_for() 返回之前也可能需要一点时间。相应地规划你的整体逻辑。

【讨论】:

    【解决方案2】:

    您确实需要一个谓词,因为您需要区分虚假唤醒和合法唤醒。

    您可以添加一个std::atomic<bool>,它会告诉您 t2 是否发送了 x 更新。当 t2 发送更新时,它也会设置这个原子布尔值。 t2 在唤醒时使用它来忽略虚假唤醒,然后将其清除。

    【讨论】:

    • 谢谢@bolov,是的,我想过,但是如果我添加一个谓词,我将无法监视 cv_status::timeout 的 wait_for 对吗?它会返回 pred() 而不是 timeout
    猜你喜欢
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    • 2022-06-16
    相关资源
    最近更新 更多