z
的非原子写操作的可见性。对于acquire
all
我对GCC-Wiki article有疑问。在标题“总体摘要”下,给出了以下代码示例:
线程1:
y.store (20);
x.store (10);
线程2:
if (x.load() == 10) {
assert (y.load() == 20)
y.store (10)
}
据说,如果所有存储都是release并且所有加载都是acquire,则线程2中的断言不会失败。这对我来说很清楚(因为线程1中x的存储与线程2中x的负载同步)。
但是现在出现了我不了解的部分。还可以说,如果所有存储都是release,而所有装入都是consume,则结果是相同的。 y的负载是否可能先于x的负载被吊起(因为这些变量之间没有依赖性)?这将意味着线程2中的断言实际上可能会失败。
C11标准的裁定如下。
评估A是依赖关系排序前 16)评估B,如果:
-A对原子对象M执行释放操作,并且在另一个线程中,B对M执行消耗操作并读取以A为首的释放序列中任何副作用写入的值或] >
-对于某些评估X,在X和X对B进行依赖之前,A是依赖关系排序的。
- 评估B,如果A与B同步,A在B之前是依序排序的,或者对于某些评估X:
评估A 线程间发生在之前
— A与X同步,并且X在B之前排序,
— A在X和X线程间发生在B之前进行排序,或者
—一个线程间发生在X之前,而X线程间发生在B之前。
- 。第一个例外是不允许串联以“先于依序进行依存关系”结尾,再以“先后依序”结尾。出现此限制的原因是,参与“之前有依存关系排序”关系的消费操作仅提供关于该消费操作实际承载依赖项的操作的排序。此限制仅适用于这种连接的最后一个结果是,任何后续的释放操作都将为先前的消耗操作提供所需的排序。第二个例外是,串联不得完全由“先后排序”组成。这种限制的原因是:(1)允许“线程间发生在”之前被暂时关闭;(2)下文定义的“发生在……之间”关系提供了完全由“先于序列”组成的关系”。
注7“线程间发生在...之前”关系描述了“在...之前排序”,“与...同步”和“依赖顺序在...之前”关系的任意串联,例外
- 评估A
评估B,如果A在B之前排序。或线程间发生在B之前。发生在…之前
- A
对M的值计算B满足条件:—可见副作用A
A发生在B之前,
-X到M没有其他副作用,因此A发生在X之前,X发生在B之前。由评估B确定的非原子标量对象M的值应为可见副作用A所存储的值。]
((已添加重点)
在下面的评论中,我将缩写如下:
线程1:
y.store (20); // Release; Evaluation A
x.store (10); // Release; Evaluation B
线程2:
if (x.load() == 10) { // Consume; Evaluation C assert (y.load() == 20) // Consume; Evaluation D y.store (10) }
为了证明断言永远不会触发,我们实际上是试图证明(15),我们有:A始终是D处的可见副作用
。根据5.1.2.4
AB DOB C SeqB D这是一个以DOB结尾,然后是SeqB的串联。尽管(16)说了什么,但这是由(17)决定的[[明确成为SeqB
not串联的ITHB。我们知道,由于A和D不在同一执行线程中,所以A不是SeqB D;因此,(18)中的两个条件都不满足HB,并且A不满足HB D。
然后得出结论,D对D不可见,因为不满足(19)的条件之一。断言可能会失败。然后,如何显示here, in the C++ standard's memory model discussion和here, Section 4.2 Control Dependencies:
((提前一些时间)线程2的分支预测变量猜测将采用if
。
0xGUNK
推测加载y
(评估D)。 (也许还没有从缓存中清除它?)。20
存储到y
(评估A)10
存储到x
(评估B)10
加载x
(评估C)if
。y == 0xGUNK
的推测性负载已落实。not禁止了它。这不同于acquire-load
int main() {
atomic_int x, y;
y.store(30, mo_seq_cst);
{{{ { y.store(20, mo_release);
x.store(10, mo_release); }
||| { r3 = x.load(mo_consume).readsvalue(10);
r4 = y.load(mo_consume); }
}}};
return 0; }
该工具报告
two一致的,无竞赛的场景,即:
成功读取y=20
,并且
读取“陈旧”的初始化值y=30
。写意圈是我的。相反,当使用
mo_acquire
进行加载时,CppMem仅报告one
一致的无竞争场景,即正确的场景:
其中读取y=20
。
memory_order_relaxed
。如果线程使用以下一种模式读取原子对象x
,则可以确保它可以看到对所有原子对象y
的所有修改,这些修改在写入x
之前已经完成。z
的非原子写操作的可见性。对于acquire
all
consume
,仅保证原子原子可见。thread 1 thread 2
z = 5 ... store(&x, 3, release) ...... load(&x, acquire) ... z == 5 // we know that z is written
z = 5 ... store(&x, 3, release) ...... load(&x, consume) ... z == ? // we may not have last value of z
z
的非原子写操作的可见性。对于acquire
all