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

时间:2016-01-20 11:00:54

标签: c++ multithreading c++11 atomic

假设有一个由主线程控制的布尔标志( 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作为循环中的标志是否会对性能产生负面影响?

1 个答案:

答案 0 :(得分:6)

只是C ++ 11标准禁止(将它们标记为未定义行为)并发访问非原子变量。

所以你需要声明这个变量原子。

注意,使用keep_running.load(std::memory_order_relaxed)作为读取值而keep_running.store(true, std::memory_order_relaxed)作为写入值将消除任何额外的性能成本,因此生成的代码将比没有原子的代码更快。

  

我想,非原子版本可能发生的最糟糕的事情就是当时标志设置正确。

可能会发生这样的情况:在你的线程中,变量将被存储到寄存器中,永远不会被重新加载(因此线程永远不会被停止)。如果没有atomic或其他特殊类型和修饰符,则允许编译器执行此操作,并且它实际上是这样做的。