首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何知道condition_variable.wait_for是由哪一种方式解除的,虚假的唤醒还是cv_status::timeout?

如何知道condition_variable.wait_for是由哪一种方式解除的,虚假的唤醒还是cv_status::timeout?
EN

Stack Overflow用户
提问于 2022-06-13 13:07:53
回答 1查看 115关注 0票数 1

据我所知,只有带有谓词的condition_variable.wait_for (因为在内部进行双重检查)才能避免被虚假唤醒所阻止,但没有谓词的版本(如果不使用时间)则不能解除阻塞。

但是,如果我想做一些事情时,只有cv_status::timeout发生了,并做了其他事情的notify_XXX?因为带有谓词的condition_variable.wait_for只返回bool,所以它无法判断是否被notify_XXXcv_status::timeout解除阻塞;尽管没有谓词的condition_variable.wait_for返回cv_status::timeout,但它无法判断是否被虚假唤醒或notify_XXX解除阻塞。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-14 13:55:57

条件变量最好作为三重变量使用。cv,互斥体和有效载荷。

如果没有有效载荷(隐式或显式),就无法确定唤醒是否是假的。

谓词版本使检查有效负载变得容易,但在一些复杂的情况下,如果不使用lambda,检查有效负载可能会更容易。因此,提供了另一个API。

修改有效载荷后,条件变量所操作的互斥对象在发送信号之前必须处于锁定状态。(例如,您可以使用互斥锁来保护有效负载;或者您可以修改有效载荷,原子化,然后锁定和解锁互斥体,然后发送信号)。否则,可能会出现假唤醒(丢失信号)的相反情况。

所有这些都很难纠正,而且很容易不小心出错。

如果您想要编写新的并发代码(特别是使用低级原语),您必须了解足够多的C++内存模型,并学习如何证明算法是正确的。因为它是一种很难编写代码并将其正确性建立在“行得通”之上的方法。

如果没有额外的数据,您已经正确地识别出无法解决这个问题。您需要添加额外的数据,并使用它来确定唤醒是假的还是真实的。那是故意的。

C++本可以将额外的数据添加到条件变量中,但是即使您没有使用它,它也会让您为此付出代价。条件变量是一个低级原语,它允许您尽可能地编写尽可能接近最优的代码,事实上,将它封装在类中可能会使某些人感到困惑。

而且有很多有效载荷。如果您有一个计数信号量,其中发送信号的数量与接收信号的数量相匹配,那么您的有效负载将是一个整数。如果您有一个闩锁或门,一旦打开,每个人都可以自由地通过它,你的有效载荷将是一个bool。

代码语言:javascript
运行
复制
struct gate {
  void wait_on_gate() const {
    auto l = lock(); 
    cv.wait( l, [&]{ return !closed; } );
  }
  // false iff it times out
  template<class Time>
  bool wait_on_gate_until(Time time) const {
    auto l = lock(); 
    return cv.wait_until( l, time, [&]{ return !closed; } );
  }
  // false iff it times out
  template<class Duration>
  bool wait_on_gate_for(Duration d) const {
    auto l = lock(); 
    return cv.wait_for( l, d, [&]{ return !closed; } );
  }
  // Once you call this, nobody waits
  void open_gate() {
    auto l = lock();
    closed = false;
    cv.notify_all();
  }
private:
  mutable std::mutex m;
  std::condition_variable cv;
  bool closed = true;
};

现在你会注意到我使用的是lambda版本。

我们可以重构到非lambda版本:

代码语言:javascript
运行
复制
  void wait_on_gate() const {
    auto l = lock(); 
    while(closed)
      cv.wait( l );
  }
  template<class Time>
  void wait_on_gate_until(Time time) const {
    auto l = lock(); 
    while(closed) {
      if (cv.wait_until(l, time) == std::cv_status::timeout)
        return !closed;
    }
    return true;
  }

这更复杂,而且作用完全一样。(假设我没有打字)。

唯一的区别是,你可以做一些花哨的事情,而这些事情可能不适合在灯笼里。例如,你可以选择说“嗯,这是假的,但当我醒着时,我会去其他地方做一些簿记,然后回来”。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72603420

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档