Tob*_*ull 14 c++ concurrency memory-model c++11 stdatomic
在x86架构上,存储到同一内存位置的总订单有,例如,请参阅此视频.C++ 11内存模型有哪些保证?
更确切地说,在
-- Initially --
std::atomic<int> x{0};
-- Thread 1 --
x.store(1, std::memory_order_release);
-- Thread 2 --
x.store(2, std::memory_order_release);
-- Thread 3 --
int r1 = x.load(std::memory_order_acquire);
int r2 = x.load(std::memory_order_acquire);
-- Thread 4 --
int r3 = x.load(std::memory_order_acquire);
int r4 = x.load(std::memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)
结果r1==1, r2==2, r3==2, r4==1是否允许(在x86以外的某些架构上)?如果我要更换所有memory_order的东西std::memory_order_relaxed怎么办?
T.C*_*.C. 10
不,这样的结果是不允许的.§1.10[intro.multithread]/p8,18(引用N3936/C++ 14;相同的文本见N3337/C++ 11第6和16段):
8对特定原子对象M的所有修改都以某种特定的总顺序出现,称为M 的修改顺序.
18如果原子对象M的值计算A发生在M的值计算B之前,并且A从M上的副作用X取其值,那么由B计算的值应该是由X存储的值或值由副作用Y存储在M上,其中Y以M的修改顺序跟随X. [ 注意:此要求称为读 - 读相干.- 结束说明 ]
在您的代码中有两个副作用,并且通过p8它们以某种特定的总顺序出现.在线程3中,计算要存储的值的值计算r1发生在之前r2,因此给定r1 == 1并且r2 == 2我们知道线程1执行的存储在线程2以修改顺序执行的存储之前x.既然如此,Thread 4如果不r3 == 2, r4 == 1与p18发生冲突就无法观察到.这与memory_order使用的无关.
p21中的注释(N3337中的第19页)是相关的:
[ 注意:前面的四个一致性要求有效地禁止编译器将原子操作重新排序到单个对象,即使两个操作都是放松加载.这有效地使大多数硬件提供的高速缓存一致性保证可用于C++原子操作.- 结束说明 ]
Per C++ 11 [intro.multithread]/6:"对特定原子对象的所有修改都以M某种特定的总顺序发生,称为修改顺序M." 因此,特定线程对原子对象的读取永远不会看到比线程已经观察到的值更"旧"的值.请注意,这里没有提及内存排序,所以这个属性适用于所有这些 - seq_cst通过relaxed.
在OP中给出的示例中,修改顺序x可以是(0,1,2)或(0,2,1).在该修改顺序中观察到给定值的线程以后不能观察到较早的值.结果r1==1, r2==2意味着修改顺序x是(0,1,2),但r3==2, r4==1暗示它是(0,2,1)一个矛盾.因此,在符合C++ 11的实现上无法获得结果.