看到Herb Sutters关于“原子武器”的优秀talk后,我对轻松原子论的例子感到有点困惑。
我随身携带 C ++内存模型中的 atomic (SC-DRF =数据竞争免费顺序一致)在加载/上获取“获取”读取。
我理解,对于加载[和商店],默认值为std::memory_order_seq_cst
,因此两者是相同的:
myatomic.load(); // (1)
myatomic.load(std::memory_order_seq_cst); // (2)
到目前为止一直很好,没有轻松的原子论(并且在听完讲话之后我永远不会使用放松的。永远。承诺。但是当有人问我时,我可能需要解释......)。
但是当我使用
时,为什么它是“放松”的语义myatomic.load(std::memory_order_acquire); // (3)
由于加载 获取且未发布,为什么这与 我唯一能想到的是我误解了加载意味着获取。如果这是真的,并且默认的 [对称商店和发布]。(1)
和(2)
不同?
seq_cst
意味着两者,这并不意味着一个完整的围栏 - 没有任何东西可以传递该指令,也不会失败?我不得不误解那部分。
答案 0 :(得分:2)
将myatomic.load(std::memory_order_acquire);
称为“放松原子”加载可能有点令人困惑,因为有std::memory_order_relaxed
您应该注意,顺序一致的负载是获取负载,但它还有一个额外的要求:顺序一致的负载也是所有seq_cst操作的全局总数的一部分。
当你处理多个原子变量时它会发挥作用:两个原子的单个修改顺序可能以不同的相对顺序出现在不同的线程上,除非强加顺序一致性。
答案 1 :(得分:1)
如果这是真的,并且默认的
seq_cst
表示两者,那不是 意味着满满的篱笆
这绝对不是两个意思,也不是“全栅栏”。
seq_cst
暗示
因此,这意味着在将两者结合在一起的操作上都只有 个:RMW原子操作。
顺序一致性还意味着这些操作是全局排序的,即:整个程序中标记为seq_cst
的所有操作均以某种顺序运行,该顺序与每个线程中的操作顺序兼容。 关于这些“顺序”操作,其他原子操作的顺序没有说明。
对原子对象执行seq_cst
操作的意图是不提供“栅栏”,该栅栏将使所有其他内存操作顺序化。
答案 2 :(得分:0)
如果您“放松”了seq_cst的某些订购要求,则会有mo_acq_rel
(以及纯获取和纯发行版)。
比mo_relaxed
更放松;无订购权。除了原子性 1 。
为最个ISA进行编译时,seq_cst负载可以使用与获取负载相同的asm;我们选择使商店昂贵而不是负担。 C/C++11 mappings to processors用于ISA,包括x86,POWER,ARMv7,ARMv8为某些ISA包括2种替代方案。为了彼此兼容,同一平台的编译器必须选择相同的策略,否则一个函数中的seq_cst存储可能会在另一个函数中的seq_cst加载时重新排序。
在内存模型包含存储缓冲区和一致性缓存的典型CPU上,如果先存储然后在同一线程中重新加载,则 seq_cst要求直到存储< em>全局对所有线程可见。这意味着在seq_cst存储之后或在seq_cst加载之前有完整的屏障(including StoreLoad)。由于廉价负载比廉价商店更有价值,因此,例如,通常的映射为商店选择x86 mov
+ mfence
。 (同样适用于加载任何 other 位置;在商店提交之前无法执行此操作。但是,商店转发可让您在全局可见之前查看自己的商店,这是Jeff Preshing的{{ 3}})
这是一个实际示例,它针对所有线程都可以同意的不同变量创建全局总操作顺序。 (x86 asm为纯负载/纯存储提供acq_rel,为lock
前缀的原子RMW指令提供seq_cst。因此Preshing的x86 asm示例完全对应于C ++ 11 mo_release
存储,而不是{{ 1}}。
ARMv8 / AArch64很有趣:它具有STLR(顺序发布存储)和LDAR(获取负载)。 可以提高效率,而不是停止所有以后的加载,直到存储缓冲区耗尽并将STLR提交到L1d缓存(全局可见性)为止。
等待冲洗只需要在LDAR执行之前进行;其他加载可以执行,甚至以后的存储也可以提交到L1d。 (Memory Reordering Caught in the Act)。为了提高效率/弱点,LDAR必须探测存储缓冲区以检查STLR存储。但是,如果您能做到这一点,那么mo_seq_cst
商店如果之后不立即对其他任何内容进行seq_cst加载,则其价格可能比x86便宜得多。
在大多数其他ISA上,恢复顺序一致性的唯一选择是完整的屏障指令(在存储之后)。这将阻止所有以后的加载和存储发生,直到所有先前的存储提交到L1d高速缓存之后。但这不是ISO C ++ mo_seq_cst
所隐含或要求的,不是,只是AArch64具有与ISO C ++一样强大的能力,而没有更强大。
(针对其他许多顺序较弱的ISA进行编译需要将acq / release提升到明显高于所需的水平,例如ARMv7需要完全限制发布存储。)
脚注1 :(就像您在古老的C ++ 11以前的代码中使用seq_cst
使用自己拥有的原子而没有任何障碍)一样。