24

我正在使用条件变量来停止一个线程,直到另一个线程完成处理它的任务队列(长话短说)。因此,在一个线程上我锁定并等待:

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)。是的,这看起来很奇怪。有谁知道为什么会发生这种情况?我是否误用了条件变量?

4

2 回答 2

44

是的,您在滥用条件变量。“条件变量”实际上只是信号机制。您还需要测试一个条件。在您的情况下,可能发生的是调用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(),那么你总是有一个错误。事实上,当 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;});
于 2013-06-04T02:40:14.557 回答
2

在讨论的基础上,我实现了一个示例来说明如何使用升压条件。

#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;
}

提升条件变量示例

于 2014-09-18T13:44:21.733 回答