在std :: thread中等待条件A或条件B.

时间:2015-11-04 15:18:46

标签: c++ multithreading c++11 stl

我有一个看似相当简单的需求,但我是使用std :: thread的新手,我不确定我是否理解。

我的线程的工作是运行循环:等到对象需要处理,然后处理它,然后等待,......

在我意识到虽然线程闲置等待新对象之前,我正准备使用condition_variable来实现它,但它没有注意到已经设置了stopThread标志。

我实际上想要一种方法wait_for_either(new_data,exit_thread),但我不确定如何优雅地实现这一点。类似队列函数的旧代码使用Windows API WaitForMultipleObjects,但我想将此作为学习C ++ 11方式的机会。

3 个答案:

答案 0 :(得分:4)

等待数据处理时,实际上是在等待条件变量发出信号。因此,当您想要退出线程时,只需发出条件变量信号,就好像stopThread标志是要处理的特殊数据一样。

代码可能如下所示:

void thread_func()
{
    std::unique_lock<std::mutex> lock(mutex);
    for (;;)
    {
        cond.wait(lock, [] () { return stopThread || !dataContainer.empty(); });
        if (stopThread)
            return; //exit thread
        //process data from dataContainer
    }
}

要插入数据:

{
    std::unique_lock<std::mutex> lock(mutex);
    dataContainer.push_back(new_data);
    cond.notify_all();
}

然后,当你想要停止线程时:

{
    std::unique_lock<std::mutex> lock(mutex);
    stopThread = true;
    cond.notify_all();
}
thread.join(); //not necessary but probably a good idea

答案 1 :(得分:1)

这是一个具有中止选项的强大数据消费循环:

while(true) {
  decltype(dataContainer) data;
  {
    std::unique_lock<std::mutex> lock(mutex);
    cond.wait(lock, [] () { return stopThread || !dataContainer.empty(); });
    if (stopThread)
      return; //exit thread
    data = std::move(dataContainer);
  }
  for (auto&& d:data) {
    if (stopThread) return; // abort
    //process data from d
  }
}

stopThread应为atomic,或者底部的for(:)循环中的访问需要使用mutex进行保护。

stopThread循环中对for(:)的访问权是可选的;没有它,它就不会中止,直到它完成它所拾取的工作捆绑。

dataContainer是以std::vector或其他形式开展的一系列工作。线程醒来,抓住所有待办事项,然后继续工作。

你也可以从dataContainer弹出一个任务而不是全部。生成的代码更简单。

要将数据排入dataContainer,您必须锁定mutex,将数据放入,然后通知:

{
  std::unique_lock<std::mutex> lock(mutex);
  dataContainer.push_back(new_data);
}
cond.notify_one();

关闭:

{
  std::unique_lock<std::mutex> lock(mutex);
  stopThread = true;
}
cond.notify_all();

请注意,即使stopThread是原子的,您也需要获取互斥锁。否则就会出现竞争状况。

答案 2 :(得分:0)

半伪代码。

std::atomic_bool programRunning;
std::condition_variable cv;
std::mutex mtx;

std::thread loopThread([&]{
   while(programRunning.load()){
       std::unique_lock<std::mutex> lock(mtx);
        if (newDataAvailable){
            //process new data
        } else{
            cv.wait(lock,[&]{ return dataAvailable || !progamRunning.load(); });
        }
   }

});

{
   std::lock_guard<std::mutex> lock(mtx);
   queueMoreData();
   cv.notify_one();
}

//on exit:
programRunning.store(false);
cv.notify_one();