一般来说,处理虚假唤醒的正确方法是什么?

问题描述 投票:2回答:2

在下面的选项中,有没有正确的方法来处理使用条件变量时的虚假唤醒?

1)使用布尔值将wait(unique_lock_ul)放入无限的while循环中

unique_lock<mutex> ul(m); 
while(!full)
  cv.wait(ul);

2)与if相同

unique_lock<mutex> ul(m); 
if(!full)
  cv.wait(ul);

3)在wait()中放置一个条件,例如使用lambda函数

unique_lock<mutex> ul(m); 
cv.wait(ul, [&](){return !full;});

如果这一切都不正确,那么如何轻松应对虚假唤醒呢?

我对C ++中的条件变量很新,我不确定我读过的一些代码是否与虚假唤醒的情况有关。

c++ c++11 condition-variable spurious-wakeup
2个回答
2
投票

简短的回答是,您的代码可能是正确的还是错误的;你没有准确显示full是如何被操纵的。

C ++代码的各个部分永远不是线程安全的。线程安全是代码的关系属性;如果它们永远不会导致竞争条件,那么两位代码可以相互保持线程安全。

但是一点代码永远不是线程安全的;说某事是线程安全的,就像说某事是“同一个高度”。


“猴子看猴子做”条件变量模式是这样的:

template<class T>
class cv_bundle {
  std::mutex m;
  T payload;
  std::condition_variable cv;
public:
  explicit cv_bundle( T in ):payload(std::move(in)) {}

  template<class Test, class Extract>
  auto wait( Test&& test, Extract&& extract ) {
    std::unique_lock<std::mutex> l(m);
    cv.wait( l, [&]{ return test(payload); } );
    return extract(payload);
  }
  template<class Setter>
  void load( Setter&& setter, bool only_one = true ) {
    bool is_set = false;
    {
      std::unique_lock<std::mutex> l(m);
      is_set = setter( payload );
    }
    if (!is_set) return; // nothing to notify
    if (only_one)
      cv.notify_one();
    else
      cv.notify_all();
  }
};

test采用T& payload并且如果有消耗的东西则返回true(即,唤醒不是假的)。

extract采取T& payload并返回您想要的任何信息。它应该通常重置有效负载。

setterT& payload将返回test的方式修改true。如果它这样做,它将返回true。如果它选择不,它返回false

所有3个都在互斥锁中访问T payload

现在,您可以为此生成变体,但这样做很难做到。例如,不要假设原子有效负载意味着您​​不必锁定互斥锁。

虽然我将这3个内容捆绑在一起,但您可以使用单个互斥锁来处理一堆条件变量,或者将互斥锁用于多个条件变量。有效载荷可以是布尔,计数器,数据向量或更外星的东西;通常,它必须始终受互斥锁保护。如果它是原子的,在被修改的值和通知之间的某个时间点内,必须锁定互斥锁,否则您可能会丢失通知。

手动循环控制而不是传入lambda是一种修改,但描述什么样的手动循环是合法的,哪些是竞争条件是一个复杂的问题。

实际上,除非我有充分的理由,否则我会避免让这种猴子看到猴子做“货物崇拜”的条件变量使用方式。然后我被迫阅读C ++内存和线程模型,这不是我的一天,这意味着我的代码很可能不会是正确的。

请注意,如果任何传入的lambda传入并回调到cv_bundle,我显示的代码将不再有效。


2
投票

处理虚假唤醒时可以使用1或3路(假设full修改受同一个互斥锁保护),除非你得到谓词条件错误,它应该是:

unique_lock<mutex> ul(m); 
cv.wait(ul, [&](){return full;});

使此代码等于变体1。

变体2并不好,因为与其他2种情况不同,虚假的唤醒等待条件不会被重新检查。

© www.soinside.com 2019 - 2024. All rights reserved.