【问题标题】:How do I use a boost condition variable to wait for a thread to complete processing?如何使用 boost 条件变量来等待线程完成处理?
【发布时间】:2013-05-30 05:07:55
【问题描述】:

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

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

【问题讨论】:

  • 代码有点混乱……第一个m_mutex和第二个m_parent.m_mutex是同一个实例吗?

标签: c++ multithreading boost


【解决方案1】:

是的,您误用了条件变量。 “条件变量”实际上只是信号机制。您还需要测试一个条件。在您的情况下,可能发生的是调用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()

这种模式非常普遍,以至于我几乎可以说,如果你没有一个包裹你的condition_variable.wait()while 循环,那么你总是有一个错误。事实上,当 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;});

【讨论】:

  • 等待线程中的boost::mutex::scoped_lock lock(m_mutex); 需要做什么? notify_one() 不接受 args。
  • 它可以向worker_is_done 提供原子写入。另一种方法是将类型声明为atomic&lt;bool&gt; 而不仅仅是bool
  • @DavidStone 如果我们在一个 1 字节分配是原子的处理器上运行代码,例如。 x86?在这种情况下,我们不需要锁,是吗?
  • @user3286661:不,您的处理器无关紧要。如果您对一个变量有两个可能重叠的访问,其中至少一个是写入,那么您的程序的行为是未定义的,除非该变量基本上是互斥锁或原子。您的硬件可能是“安全的”,但您的编译器可以在假设您没有做任何未定义的事情的情况下进行它想要的任何优化。例如,它可能会将多个变量合二为一,因为您无法区分(除非您有未定义的行为)。
  • @DavidStone 您能否给this写一个答案?非常感谢。
【解决方案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;
}

Boost condition variable example

【讨论】:

  • 在将worker_is_done设置为true之前不应该锁定workFunction吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-17
  • 2021-05-14
  • 1970-01-01
  • 2011-06-05
  • 1970-01-01
  • 2021-11-07
相关资源
最近更新 更多