使用std :: conditional_variable在条件上等待

Jus*_*ber 6 c++ multithreading condition-variable blocking c++11

为简单起见,我们假设我们只有一个条件变量来匹配由布尔值反映的单个条件.

1)为什么std::condition_variable::wait(...)在发送"通知"后才重新锁定互斥锁?

2)看到"1)"中的行为,这是否意味着当你这样做std::condition_variable::notify_all时只会使所有等待的线程被解锁/唤醒...但是按顺序而不是一次完成所有?如果是这样,可以做些什么来一次完成这一切?

3)如果我只关心线程睡眠直到满足条件并且不关心任何互斥锁获取,我该怎么办?是否有替代方案或当前的std::condition_variable::wait(...)方法是否应该被攻击?

如果要使用"hackery",这个函数是否可以解除条件中所有等待线程的阻塞,并且可以从任何(每个线程)线程调用它:

//declared somehwere and modified before sending "notify"(ies)
std::atomic<bool> global_shared_condition_atomic_bool;

//the single(for simplicity in our case) condition variable matched with the above boolean result
std::condition_variable global_shared_condition_variable;

static void MyClass:wait()
{
    std::mutex mutex;
    std::unique_lock<std::mutex> lock(mutex);

    while (!global_shared_condition_atomic_bool) global_shared_condition_variable.wait(lock);
}
Run Code Online (Sandbox Code Playgroud)

它会被随机的"等待"线程调用,如下所示:

void random_thread_run()
{
    while(someLoopControlValue)
    {
        //random code...
        MyClass:wait(); //wait for whatever condition the class+method is for.
        //more random code...
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

门类

#ifndef Gate_Header
#define Gate_Header

#include <mutex>
#include <condition_variable>

class Gate
{
public:
    Gate()
    {
        gate_open = false;
    }

    void open()
    {
        m.lock();
        gate_open = true;
        m.unlock();

        cv.notify_all();
    }

    void wait()
    {
        std::unique_lock<std::mutex> lock(m);

        while (!gate_open) cv.wait(lock);
    }

    void close()
    {
        m.lock();
        gate_open = false;
        m.unlock();
    }

private:
    std::mutex m;
    std::condition_variable cv;
    bool gate_open;
};

#endif
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 8

条件变量虚假地唤醒事物.

必须有一个互斥锁,它必须保护某种类型的消息才能使它们工作,或者你无法保证发生任何这种唤醒.

大概是这样做的,因为非虚假版本的有效实现最终无论如何都会以这种虚假版本的形式实现.

如果您无法使用互斥锁保护消息编辑(即,没有同步,则消息的状态是未定义的行为.这可能导致编译器优化内存读取以在第一次读取后跳过它.

即使排除了未定义的行为(想象你使用原子),也存在设置消息,发生通知的竞争条件,并且如果您未能在两者之间的时间内获取互斥锁,则等待通知的任何人都会看到消息被设置设置变量并通知条件变量.

除极端情况外,您通常希望使用lambda版本wait.

除非您同时审核通知代码和等待代码,否则无法审核条件变量代码.

struct gate {
  bool gate_open = false;
  mutable std::condition_variable cv;
  mutable std::mutex m;

  void open_gate() {
    std::unique_lock<std::mutex> lock(m);
    gate_open=true;
    cv.notify_all();
  }
  void wait_at_gate() const {
    std::unique_lock<std::mutex> lock(m);
    cv.wait( lock, [this]{ return gate_open; } );
  }
};
Run Code Online (Sandbox Code Playgroud)

要么

  void open_gate() {
    {
      std::unique_lock<std::mutex> lock(m);
      gate_open=true;
    }
    cv.notify_all();
  }
Run Code Online (Sandbox Code Playgroud)

  • @JustinBieber 那是因为你是歌手,而不是程序员。2-arg 形式更简单且等效;没有流量控制,只是一个测试功能。互斥锁保护对条件变量*和*正在测试的值的访问。有一个狭窄的竞争条件,涉及在设置布尔值和发送通知之间的任何点都不持有互斥体,从而开始等待的线程永远不会醒来。 (2认同)