如何使用boost条件变量等待线程完成处理?

MM.*_*MM. 23 c++ multithreading boost

我使用条件变量来停止一个线程,直到另一个线程完成处理它的任务队列(长篇故事).所以,在一个线程上我锁定并等待:

boost::mutex::scoped_lock lock(m_mutex);
m_condition.wait(lock);
Run Code Online (Sandbox Code Playgroud)

一旦另一个线程完成了它的任务,它就会向等待线程发出如下信号:

boost::mutex::scoped_lock lock(m_parent.m_mutex);
m_parent.m_condition.notify_one();
Run Code Online (Sandbox Code Playgroud)

我看到的问题是等待线程不会停止等待,除非我在其后面的指令上设置断点(我正在使用xcode,fyi).是的,这看起来很奇怪.有谁知道为什么会发生这种情况?我错误地使用了条件变量吗?

Wan*_*gic 43

是的,你正在滥用条件变量."条件变量"实际上只是信号机制.您还需要测试一个条件.在你的情况下,可能发生的事情是调用notify_one()的线程实际上在调用wait()甚至启动的线程之前完成.(或者至少,notify_one()呼叫在呼叫之前发生wait().)这称为"错过唤醒".

解决方案是实际上有一个包含你关心的条件的变量:

bool worker_is_done=false;

boost::mutex::scoped_lock lock(m_mutex);
while (!worker_is_done) m_condition.wait(lock);
Run Code Online (Sandbox Code Playgroud)

boost::mutex::scoped_lock lock(m_mutex);
worker_is_done = true;
m_condition.notify_one();
Run Code Online (Sandbox Code Playgroud)

如果worker_is_done==true在另一个线程开始等待之前,那么你将直接通过while循环而没有调用wait().

这种模式是如此常见,以至于我几乎可以说,如果你没有while环绕你的condition_variable.wait()那么你总是有一个bug.事实上,当C++ 11采用类似于boost :: condtion_variable的东西时,他们添加了一种新的wait(),它接受谓词lambda表达式(实际上它while为你做了循环):

std::condition_variable cv;
std::mutex m;
bool worker_is_done=false;


std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return worker_is_done;});
Run Code Online (Sandbox Code Playgroud)