我是否必须使用atomic <bool>作为“exit”bool变量?</bool>

时间:2013-04-19 18:55:07

标签: c++ c++11 atomic

我需要为另一个线程设置一个标志才能退出。另一个线程会不时检查退出标志。我是否必须使用原子作为旗帜,或者仅仅是一个普通的布尔就足够了(为什么(如果我使用普通布尔可能会出错的例子)?

#include <future>
bool exit = false;
void thread_fn()
{
    while(!exit)
    {
        //do stuff
        if(exit) break;
        //do stuff
    }
}
int main()
{
    auto f = std::async(std::launch::async, thread_fn);
    //do stuff
    exit = true;
    f.get();
}

3 个答案:

答案 0 :(得分:26)

  

我是否必须使用atomic来“退出”bool变量?

即可。

使用atomic<bool>,或通过(例如)std::mutex使用手动同步。您的程序当前包含数据竞争,其中一个线程可能正在读取变量而另一个线程正在编写它。这是未定义的行为。

根据C ++ 11标准的第1.10 / 21段:

  

如果程序的执行在不同的线程中包含两个冲突的操作,则会执行数据竞争,   其中至少有一个不是原子的,也不会发生在另一个之前。任何此类数据竞赛都会产生   未定义的行为

冲突”的定义见第1.10 / 4段:

  

两个表达式评估冲突如果其中一个修改了内存位置(1.7)而另一个修改了内存位置   访问或修改相同的内存位置。

答案 1 :(得分:12)

是的,您必须进行一些同步。正如您所说,最简单的方法是使用atomic<bool>

正如@AndyProwl所说的那样,语言定义说在这里不使用原子会给出未定义的行为。这有很好的理由。

首先,通过线程切换可以中断对变量的读取或写入;另一个线程可能会看到部分写入的值,或者如果它修改了值,原始线程将看到一个混合值。其次,当两个线程在不同的核心上运行时,它们具有单独的缓存;写入值会将其存储在缓存中,但不会更新其他缓存,因此线程可能看不到其他线程写入的值。第三,编译器可以根据它看到的内容重新组织代码;在示例代码中,如果循环内没有任何内容改变exit的值,编译器没有任何理由怀疑该值会改变;它可以将循环转换为while(1)

Atomics解决了所有这三个问题。

答案 2 :(得分:-4)

实际上,在这个特定的例子中,普通布尔没有出错。唯一的通知是将bool exit变量声明为volatile以将其保存在内存中。 CISC和RISC架构都将bool读/写实现为严格的原子处理器指令。现代多核处理器也具有先进的智能缓存实现。所以,任何记忆障碍都是不必要的。标准引用不适用于这种特殊情况,因为它只处理一个写作和唯一一个帖子的读取。