问题描述
该标准定义了几个"在此之前发生"关系,这些关系将良好的旧"在此之前排序"扩展到多个线程:
推荐答案
这是我目前的理解,可能不完整或不正确。如能核实,将不胜感激。
C++20已将
strongly happens before
重命名为simply happens before
,并为strongly happens before
引入了更宽松的新定义,从而降低了排序。
Simply happens before
用于推断代码中是否存在数据竞争。(实际上,这显然是"以前发生的",但如果没有消费操作,这两种操作是等价的,标准不鼓励使用消费操作,因为大多数(所有?)主要编译器将它们视为获取。)较弱的
strongly happens before
用于推断seq-cst操作的全局顺序。
此更改是在提案P0668R5: Revising the C++ memory model中引入的,该提案基于Lahav等人的论文Repairing Sequential Consistency in C/C++11(我没有完全阅读)。
该提案解释了做出更改的原因。长话短说,大多数编译器在Power和ARM体系结构上实现原子的方式在极少数边缘情况下被证明是不一致的,而且修复编译器有性能成本,因此他们改为修复标准。
仅当您在同一原子变量上混合使用seq-cst操作和获取-释放操作时(即,如果获取操作从seq-cst存储区读取值,或seq-cst操作从发布存储区读取值),更改才会影响您。
如果您不以这种方式混合操作,则不会受到影响(即可以将
simply happens before
和strongly happens before
视为等效)。更改的要点是seq-cst操作与相应的获取/释放操作之间的同步不再影响此特定seq-cst操作在全局seq-cst顺序中的位置,但同步本身仍然存在。
这使得此类seq-cst操作的seq-cst顺序非常没有意义,请参见下面的内容。
提案如下所示,我试着解释一下我对它的理解:
atomic_int x = 0, y = 0; int a = 0, b = 0, c = 0; // Thread 1 x.store(1, seq_cst); y.store(1, release); // Thread 2 b = y.fetch_add(1, seq_cst); // b = 1 (the value of y before increment) c = y.load(relaxed); // c = 3 // Thread 3 y.store(3, seq_cst); a = x.load(seq_cst); // a = 0
注释指示此代码可以执行的一种方式,这是标准过去禁止的(在此更改之前),但实际上可能会发生在受影响的体系结构上。
执行过程如下:
.-- 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); <-' | | | : | 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 <-' <-'
其中:
右侧的括号数字显示全局序号-CST顺序。
左侧的箭头显示值如何在某些加载和存储之间传播。
中间的箭头显示:
- 'Sequenced before',很老的单线程求值顺序。
- ‘同步于’,释放-获取同步(seq-cst加载计数为获取操作,seq-cst存储计数为释放操作)。
这两个加在一起构成"简单地发生在此之前"。
右侧的箭头基于中间的箭头,它们显示:
新定义的"强发生在此之前"关系。
'Coherence-ordered before',本方案中引入的新关系,仅用于定义全局seq-cst顺序,显然不强制同步(不同于Release-Acquisition操作)。
它似乎包括了影响全球SEQ-CST秩序的所有事情,而不是"之前发生的事情"。在本例中,如果加载看不到存储写入的值,则加载将先于存储进行,这是常识。全局序号-CST顺序与两者一致。
请注意,在此图中,
b = y.fetch_add(1, seq_cst);
之前没有强烈的事件发生,因此在全局seq-cst顺序中没有必须在其之前的任何内容,因此可以将其向上移动到seq-cst顺序的开始,这就是最终发生的情况,即使它读取后面(按此顺序)操作生成的值。这篇关于与(简单地)发生在';之前相比,';强烈发生在';之前有什么意义呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!