我读了这个Q&A:What is the significance of 'strongly happens before' compared to '(simply) happens before'?
作者给出了一个有趣的评估的大纲,这个评估在C20之前是不可能的,但显然可以从C20开始:
.-- T3 y.store(3, seq_cst); --. (2)
| | | strongly
| | sequenced before | happens
| V | before
| T3 a = x.load(seq_cst); // a = 0 --. <-' (3)
| : coherence-
| : ordered
| : before
| T1 x.store(1, seq_cst); <-' --. --. (4)
| | |st |
| | sequenced before |h |
| V |b |
| . T1 y.store(1, release); <-' | (x)
| | : | strongly
| | : synchronizes with | happens
| | V | before
| > T2 b = y.fetch_add(1, seq_cst); // b = 1 --. | (1)
| | |st |
| | sequenced before |h |
| V |b |
'-> T2 c = y.load(relaxed); // c = 3 <-' <-'
字符串
右边的数字表示可能的seq_cst
阶数(为了方便,我加上了(x);该行不参与SC订单,因为它不是SC操作)。
我试图理解这个例子中y
的修改顺序是什么,但我不知道如何确定它。(或者对于此评估,y
是否有多个可能的修改顺序?..)
更一般地说,C++中原子变量的修改顺序是如何定义的?比如说https://en.cppreference.com/w/cpp/atomic/memory_order的
写-写一致性:如果修改某个原子M的求值A(写)发生在修改M的求值B之前,那么按照M的修改顺序,A出现在B之前
因此,修改顺序似乎必须与write-write happens-before-one一致。
它是唯一定义修改顺序的东西吗?
在上面的例子中,AFAIU在(2)和(1)之间没有happens-before;那么在y
的修改顺序中,哪个是第一个?
是否为y
(x 1 2)的模阶(对于此评估)?
我相信这也可能有助于推理seq_cst
顺序。
1条答案
按热度按时间7eumitmz1#
对象的修改顺序是线程在运行
while(1) { y.load(relaxed); }
的紧密循环中旋转时看到的顺序,并且碰巧看到了每个更改。(这并不是实际观察它的有用方法,但每个对象都有自己的修改顺序,所有线程都可以始终同意,就像在真实的的CPU上一样,由于MESI独占所有权需要将存储提交到L1 d缓存。或者通过POWER CPU上SMT线程之间的私有存储转发提前看到它。)一些随机事实:
relaxed
relaxed
。我认为这个计算显示了实际的有效顺序,所以
y
的mod顺序只是从上到下读取,操作(2) (x) (1)
以该顺序存储的值。(因为它使用了足够多的seq_cst
操作,所有线程都可以同意顺序,并且显示了一些其他事情最终将发布存储(x)
排序在seq_cst
存储(2)
之后。这个eval顺序是说
(2)
存储在(x)
存储之前变得可见,所以(x)
存储取代了它。在
y.fetch_add
(1)
之前,尘埃已经尘埃落定,否则它将与(2)
同步,而不是(x)
。更正,显然他们表明
(x) (1) (2)
的修改顺序是法律的的,尽管在(2)
(存储3)和最后的y.load()
之间存在不同的happens-before链。因此,该存储在fetch_add
之后、load
之前对T2可见。