我正在使用条件变量来停止线程,直到另一个线程完成处理它的任务队列(长篇故事)。所以,在一个线程上我锁定并等待:
boost::mutex::scoped_lock lock(m_mutex);
m_condition.wait(lock);
一旦另一个线程完成了它的任务,它就会发出如下信号:
boost::mutex::scoped_lock lock(m_parent.m_mutex);
m_parent.m_condition.notify_one();
我看到的问题是等待线程不会停止等待,除非我在其后的指令上设置断点(我正在使用xcode,fyi)。是的,这看起来很奇怪。有谁知道为什么会发生这种情况?我错误地使用了条件变量吗?
答案 0 :(得分: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);
和
boost::mutex::scoped_lock lock(m_mutex);
worker_is_done = true;
m_condition.notify_one();
如果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;});
答案 1 :(得分:3)
我已经在讨论中实现了一个说明如何使用boost条件的示例。
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
boost::mutex io_mutex;
bool worker_is_done = false;
boost::condition_variable condition;
void workFunction()
{
std::cout << "Waiting a little..." << std::endl;
boost::this_thread::sleep(boost::posix_time::seconds(1));
worker_is_done = true;
std::cout << "Notifying condition..." << std::endl;
condition.notify_one();
std::cout << "Waiting a little more..." << std::endl;
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
int main()
{
boost::mutex::scoped_lock lock(io_mutex);
boost::thread workThread(&workFunction);
while (!worker_is_done) condition.wait(lock);
std::cout << "Condition notified." << std::endl;
workThread.join();
std::cout << "Thread finished." << std::endl;
return 0;
}