假设有一个由主线程控制的布尔标志( keep_running )。另一个线程无限循环,直到此标志变为false。
int main() {
bool keep_running(true);
std::thread run( [](bool &keep_running)
{
while(keep_running)
{
// do work
}
}, std::ref(keep_running) );
// do other work
keep_running = false;
run.join();
return 0;
}
该标志应该是原子的吗?
std::atomic<bool> keep_running
我想,非原子版本可能发生的最糟糕的情况是该标志在
时设置正确while(keep_running)
已执行。在这种情况下,循环继续运行一次(非严格需要)迭代。但就我而言,这是可以接受的。
是否存在上述代码可能出错的情况?
编辑:
我出于性能原因(以及没有错误)对此感兴趣。那么,使用std :: atomic作为循环中的标志是否会对性能产生负面影响?
答案 0 :(得分:6)
只是C ++ 11标准禁止(将它们标记为未定义行为)并发访问非原子变量。
所以你需要声明这个变量原子。
注意,使用keep_running.load(std::memory_order_relaxed)
作为读取值而keep_running.store(true, std::memory_order_relaxed)
作为写入值将消除任何额外的性能成本,因此生成的代码将比没有原子的代码更快。
我想,非原子版本可能发生的最糟糕的事情就是当时标志设置正确。
可能会发生这样的情况:在你的线程中,变量将被存储到寄存器中,永远不会被重新加载(因此线程永远不会被停止)。如果没有atomic
或其他特殊类型和修饰符,则允许编译器执行此操作,并且它实际上是这样做的。