我有一个看似相当简单的需求,但我是使用std :: thread的新手,我不确定我是否理解。
我的线程的工作是运行循环:等到对象需要处理,然后处理它,然后等待,......
在我意识到虽然线程闲置等待新对象之前,我正准备使用condition_variable
来实现它,但它没有注意到已经设置了stopThread
标志。
我实际上想要一种方法wait_for_either(new_data,exit_thread)
,但我不确定如何优雅地实现这一点。类似队列函数的旧代码使用Windows API WaitForMultipleObjects
,但我想将此作为学习C ++ 11方式的机会。
答案 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();