我正在阅读Bjarne Stroustrup的C++ 11 FAQ,我无法理解内存模型部分中的示例.
他给出了以下代码片段:
// start with x==0 and y==0 if (x) y = 1; // thread 1 if (y) x = 1; // thread 2
FAQ说这里没有数据竞争.我不明白.内存位置x
由线程1读取并由线程2写入而没有任何同步(并且同样适用y
).这是两次访问,其中一次是写入.这不是数据竞争的定义吗?
此外,它说"每个当前的C++编译器(我所知道的)给出了正确答案." 这个正确答案是什么?根据一个线程的比较是在另一个线程的写入之前或之后发生(或者另一个线程的写入是否对读取线程可见),答案是否会有所不同?
内存位置
x
由线程2写入
是真的吗?你为什么这么说?
如果y
是0,则x
是不按线程2.写入并y
同样开出0,x
不能非零除非在某种程度上y
是非零"之前"线程1下运行,并且不能发生.这里的一般观点是,不执行的条件写入不会导致数据竞争.
不过,这是内存模型的一个重要事实,因为不允许线程编译的编译器(假设y
不是易失性的)将代码转换if (x) y = 1;
为int tmp = y; y = 1; if (!x) y = tmp;
.然后有将是数据的比赛.我无法想象为什么它会想要进行那种确切的转换,但这并不重要,重点是非线程环境的优化器可以做违反线程内存模型的事情.因此,当Stroustrup说他所知道的每个编译器给出了正确的答案时(就在C++ 11的线程模型下,就是这样),这是关于C++ 11线程编译器准备就绪的一个非平凡的陈述.
if (x) y = 1
将是一个更现实的转变y = x ? 1 : y;
.我相信这会导致您的示例中的数据竞争,并且在分配的标准中没有特殊处理,y = y
这使得对于y
在另一个线程中的读取执行不安全而言是安全的.您可能会发现很难想象它不起作用的硬件,无论如何我可能是错的,这就是为什么我使用上面不同的例子,这不太现实,但有一个明显的数据竞争.
// start with x==0 and y==0 if (x) y = 1; // thread 1 if (y) x = 1; // thread 2
既然x和y都不是真的,另一个也不会被设置为真.无论执行指令的顺序如何,(正确)结果总是x保持为0,y保持为0.