布尔标志应该始终是原子的吗?
Should a boolean flag always be atomic?
假设有一个由主线程控制的布尔标志(keep_running)。另一个线程无限循环,直到这个标志变为假。
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 作为标志会对性能产生负面影响吗?
只是 C++11 标准禁止(将它们标记为 未定义行为)并发访问 non-atomic 变量。
所以你需要声明这个变量是原子的。
请注意,使用 keep_running.load(std::memory_order_relaxed)
读取值和 keep_running.store(true, std::memory_order_relaxed)
写入值将消除任何额外的性能成本,因此生成的代码将与没有原子的代码一样快。
I imagine, the worst which can happen to the non-atomic version would be that the flag gets set right at the time.
在您的线程中,变量可能会存储到寄存器中并且永远不会重新加载(因此线程永远不会停止)。在没有 atomic
或其他特殊类型和修饰符的情况下,允许编译器这样做,而且它确实这样做了。
假设有一个由主线程控制的布尔标志(keep_running)。另一个线程无限循环,直到这个标志变为假。
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 作为标志会对性能产生负面影响吗?
只是 C++11 标准禁止(将它们标记为 未定义行为)并发访问 non-atomic 变量。
所以你需要声明这个变量是原子的。
请注意,使用 keep_running.load(std::memory_order_relaxed)
读取值和 keep_running.store(true, std::memory_order_relaxed)
写入值将消除任何额外的性能成本,因此生成的代码将与没有原子的代码一样快。
I imagine, the worst which can happen to the non-atomic version would be that the flag gets set right at the time.
在您的线程中,变量可能会存储到寄存器中并且永远不会重新加载(因此线程永远不会停止)。在没有 atomic
或其他特殊类型和修饰符的情况下,允许编译器这样做,而且它确实这样做了。