2015-11-04 38 views
0

我有一个相当简单的需求,但我对使用std :: thread并不确定我理解它是否正确。在std :: thread中等待条件A或条件B

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

我正要实施这一使用condition_variable我才意识到,虽然螺纹正坐着等待一个新的对象,它不会注意到已经设置了一个stopThread标志。

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

回答

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(); 
+0

我知道你在使用lambdas,但是'[&] {...}'语法是什么? –

+0

通过引用抓住一切,没有参数 –

+0

我会做一个永久循环,等待,并打破自己。另外,你应该让你的'newDataAvailable'具有相同的名字。 ;)接下来,您可能不希望在整个处理数据期间持有互斥锁;这使得排队等待新数据的人们必须等待旧数据的处理。 – Yakk

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

我想你的意思是使用'wait'而不是'wait_for'。 'wait_for'需要指定的时间。 – NathanOliver

+0

这将使用'condition_var_any',对吧?我假设条件函数是简单地周期性地调用的 - 这个函数是否需要线程安全或是有保证的? –

+0

@NathanOliver:是的,当然会纠正。 – rodrigo

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

stopThreadatomic或在底部需要有mutex加以防护在for(:)环路接。

for(:)循环中访问stopThread是可选的;没有它,它将不会中止,直到它完成了它所拾取的一揽子工作。

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是原子,你需要获取互斥锁。另外还有一个竞赛条件。

+0

我喜欢如何拉出数据然后释放锁定,以便在处理当前数据时可以排队更多条目。我可以在拉出数据后手动释放锁以获得相同的效果吗? –

+0

@ Mr.Boy当然,这可以工作。明确地解决锁定状态时要小心;有限范围的锁更容易推理。 – Yakk

相关问题