在x86体系结构中,存储到相同内存位置的存储有一个总的顺序,例如,参见this video。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);是否允许结果r1==1, r2==2, r3==2, r4==1 (在x86以外的某些体系结构上)?如果我用std::memory_order_relaxed代替所有的std::memory_order_relaxed呢?
发布于 2014-12-06 16:19:48
不,这种结果是不允许的。§1.10导入.多线程/p8,18 (引用N 3936/C++14;N 3337/C++11的第6和16段也有相同的案文):
8对某一特定原子物体M的所有修改都以某种特定的全序发生,称为M的修改顺序。 18如果一个原子物体M的值计算A发生在M的值计算B之前,而A从M的副效应X获得它的值,则B计算的值要么是X存储的值,要么是由M上的副作用Y存储的值,其中Y以M的修改顺序跟随X:这一要求称为读读一致性。-end注记
在您的代码中有两个副作用,通过p8,它们以特定的总体顺序出现。在Thread 3中,计算存储在r1中的值的值计算发生在r2的值之前,因此,给定r1 == 1和r2 == 2,我们知道线程1执行的存储以x的修改顺序先于线程2执行的存储。在这种情况下,Thread 4不能在不与p18发生冲突的情况下观察r3 == 2, r4 == 1。这与所使用的memory_order无关。
在p21 (p19 in N3337)中有一个注释是相关的:
注意:前面的四个一致性要求实际上不允许编译器将原子操作重新排序到单个对象,即使这两个操作都是轻松加载的。这有效地使大多数硬件提供的缓存一致性保证可用于C++原子操作。-end注记
发布于 2014-12-06 16:20:00
多线程/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的实现上是不可能的。
发布于 2018-06-03 17:46:48
考虑到C++11规则肯定不允许这样做,下面是一种更定性/直观的理解方法:
如果x没有更多的商店,最终所有的读者都会同意它的价值。(这两家商店中有一家排在第二位)。
如果不同的线程可能不同意这个顺序,那么要么他们会永久地/长期地不同意这个值,要么一个线程可以看到这个值第三次改变(幻影存储)。
幸运的是,C++11不允许任何一种可能性。
https://stackoverflow.com/questions/27333311
复制相似问题