我需要为另一个线程退出的标志。 其他线程检查出口标志不时。 我一定要使用原子的标志或只是一个普通的布尔是够了,为什么(有什么,如果我使用普通布尔恰好可能出错的例子)?
#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();
}
我一定要使用原子的“退出”布尔变量?
是 。
既可以使用atomic<bool>
,或通过使用手动同步(例如)一个std::mutex
。 你的程序目前包含一个数据的比赛 ,有一个线程可能阅读的变量,而另一个线程在写它。 这是未定义的行为。
每一段中的C ++ 11标准的1.10 / 21:
一个程序的执行包含数据种族,如果它包含在不同的线程两个相互矛盾的操作,其中至少一个是不原子,和既不在另一个之前发生。 任何这样的数据比赛结果不确定的行为 。
的“ 冲突的 ”的定义中第1.10段给出/ 4:
两个表达评价冲突如果它们中的一个修改的存储器位置(1.7),而另一个存取或修改相同的存储器位置。
是的,你必须有一些同步。 最简单的方法是,如你所说,用atomic<bool>
。
形式上,作为@AndyProwl说,语言定义说,不使用原子这里给出了不确定的行为。 有很好的理由。
首先,将变量的读或写可以被中断通过线程切换中途; 其他线程可能会看到一个部分,写入值,或者如果它修改了值,原来的线程将看到一个混合值。 其次,当两个线程在不同内核上运行,它们有不同的缓存; 写一个值,并将其存储在缓存中,但不会更新其他缓存,所以一个线程可能看不到被另一个线程写入的值。 第三,编译器可以基于它看到的重组代码; 示例代码,如果没有内循环改变的值exit
,编译器没有任何理由怀疑该值将发生变化; 它可以把循环入while(1)
原子能解决所有这三个问题。
其实,一切正常,在这个特殊的例子平原布尔。 唯一的通知是声明布尔出入口变量的波动保持在内存中。 既CISC和RISC架构实现BOOL读/写为严格原子处理器指令。 也是现代multocore处理器已经高级智能高速缓存implementstion。 所以,任何记忆力障碍是没有必要的。 因为它是唯一一个写和从只有一个线程读取交易的标准引用是不适合这种特殊情况。