布尔标志应该始终是原子的吗?

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 或其他特殊类型和修饰符的情况下,允许编译器这样做,而且它确实这样做了。