请参阅以下代码:
std::mutex mutex;
std::condition_variable cv;
std::atomic<bool> terminate;
// Worker thread routine
void work() {
while( !terminate ) {
{
std::unique_lock<std::mutex> lg{ mutex };
cv.wait(lg);
// Do something
}
// Do something
}
}
// This function is called from the main thread
void terminate_worker() {
terminate = true;
cv.notify_all();
worker_thread.join();
}
是否可能发生以下情况?
terminate_worker()
;
terminate
设置为true
,然后发信号通知工作线程。terminate
加载。在此步骤中,主线程对 terminate
的更改尚未显示,因此工作线程决定等待另一个信号。我想知道这是可能的。据我所知,std::atomic
只保证没有竞争条件,但记忆顺序是另一回事。问题:
terminate
不是原子变量而只是bool
,这是否可行?或者原子性与此无关?谢谢。
答案 0 :(得分:2)
我不相信,你所描述的是可能的,cv.notify_all()
afaik(如果我错了请纠正我)与wait()
同步,所以当工作线程醒来时,它会看到对terminate
的更改。
<强>然而强>
死锁可能发生在以下方面:
工作线程(WT)确定terminate
标志仍为假。
主线程(MT)设置terminate
标记并调用cv.notify_all()
。
join
并阻止。cv.wait()
)并阻止。 解决方案:
虽然您在调用cv.notify时不必按住锁定,但
terminate
(即使它是原子)时必须持有锁wait
的实际调用。 这就是为什么有wait
形式在它将线程发送到睡眠状态之前执行此检查的原因。
更正的代码(变化很小)可能如下所示:
// Worker thread routine
void work() {
while( !terminate ) {
{
std::unique_lock<std::mutex> lg{ mutex };
if (!terminate) {
cv.wait(lg);
}
// Do something
}
// Do something
}
}
// This function is called from the main thread
void terminate_worker() {
{
std::lock_guard<std::mutex> lg(mutex);
terminate = true;
}
cv.notify_all();
worker_thread.join();
}