我已经阅读了很多文章,并观看了一些Youtube视频C++原子和内存模型(ConCpp 17,14)。
当我阅读《并发行动》第5.3.3节 RELAXED ORDERING 时,我仍然无法理解作者根据他的假设提供的示例。
作者的假设
假设我们看到的代码未重新排序。
示例代码:
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
x.store(true,std::memory_order_relaxed); // 1
y.store(true,std::memory_order_relaxed); // 2
}
void read_y_then_x()
{
while(!y.load(std::memory_order_relaxed)); // 3
if(x.load(std::memory_order_relaxed)) // 4
++z;
}
int main() {
x=false;
y=false;
z=0;
std::thread a(write_x_then_y);
std::thread b(read_y_then_x);
a.join();
b.join();
assert(z.load()!=0); // 5
}
从此链接:https://www.developerfusion.com/article/138018/memory-ordering-for-atomic-operations-in-c0x/
为什么
x.load(relaxed)
返回false
但y.load(relaxed)
返回true
吗?作者的结论
问:为什么x的负载可以为假?
作者得出结论,断言可以触发。因此,
z
可以是0
。因此,
if(x.load(std::memory_order_relaxed))
:x.load(std::memory_order_relaxed)
是false
。但是无论如何,
while(!y.load(std::memory_order_relaxed));
会使y
成为true
。如果我们不对(1)和(2)的代码序列重新排序,怎么可能
y
为true但x
仍不存储? 如何理解作者提供的数字?
基于
the store of x (1) happens-before the store of y (2)
,如果x.store(relaxed)
发生在y.store(relaxed)
之前,则x
现在应该为true
。但是,为什么x
仍然是false
,即使y
是true
呢? 最佳答案
您和 friend 都同意x=false
和y=false
。有一天,您给他寄了一封信,告诉他x=true
。第二天,您给他寄了一封信,告诉他y=true
。您绝对可以按正确的顺序给他寄信。
稍后,您的 friend 收到您的来信,说y=true
。现在,您的 friend 对x
了解多少?他可能已经收到了告诉他x=true
的信。但是也许邮政系统暂时丢失了它,他明天就可以收到它。因此,对于他来说,当他收到x=false
字母时,x=true
和y=true
都是有效的可能性。
因此,回到硅世界。线程之间的内 stub 本无法保证其他线程的写入会以任何特定顺序增加,因此“延迟的x”完全有可能。添加atomic
并使用relaxed
所做的所有事情都会阻止两个线程在单个变量上争分夺秒地成为未定义的行为。它对订购根本不做任何保证。多数民众赞成在更强的顺序。
或者,以一种稍微粗略的方式,看一下我的MSPaint技能:
在这种情况下,紫色箭头(从第一个线程到第二个线程的“x”流)为时已晚,而绿色箭头(y交叉)发生得很快。
关于c++ - 如何在std::memory_order(C++)中理解RELAXED ORDERING,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55680665/