完整/通用内存屏障是屏障之前指定的所有LOAD和STORE操作似乎在屏障之后指定的所有LOAD和STORE操作之前相对于系统的其他组件发生的屏障。
根据cppreference,memory_order_seq_cst
等于memory_order_acq_rel
加上所有已标记的操作的总修改顺序。但据我所知,C ++ 11中的获取和释放栏都没有强制执行#StoreLoad(加载后存储)排序。发布围栏要求以后的任何写入都不能重新排序先前的读/写;获取围栏要求不能对任何先前的读取重新排序后续读/写。如果我错了,请纠正我;)
举个例子,
atomic<int> x;
atomic<int> y;
y.store(1, memory_order_relaxed); //(1)
atomic_thread_fence(memory_order_seq_cst); //(2)
x.load(memory_order_relaxed); //(3)
优化编译器是否允许将指令(3)重新排序到(1)之前,以使其有效看起来像:
x.load(memory_order_relaxed); //(3)
y.store(1, memory_order_relaxed); //(1)
atomic_thread_fence(memory_order_seq_cst); //(2)
如果这是一个有效的转换,那么它证明atomic_thread_fence(memory_order_seq_cst)
并不一定包含完整障碍所具有的语义。
答案 0 :(得分:2)
atomic_thread_fence(memory_order_seq_cst)
始终会产生全屏障。
MFENCE
hwsync
mf
dmb ish
sync
主要的事情:观察线程可以简单地以不同的顺序观察,并且在观察到的线程中使用的是什么围栏并不重要。
优化编译器是否允许将指令(3)重新排序为 之前(1)?
不,不允许。但是在全局可见的多线程程序中,这是真的,只有在:
memory_order_seq_cst
进行原子读/写操作atomic_thread_fence(memory_order_seq_cst);
- 但这种方法一般不保证顺序一致性,因为顺序一致性是更强有力的保证工作草案,编程语言C ++标准2016-07-12:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
§29.3顺序和一致性
§29.3/ 8
[注意:memory_order_seq_cst仅确保a的顺序一致性 没有数据竞赛且仅使用的程序 memory_order_seq_cst操作。任何使用较弱的订购都会 除非使用极其谨慎,否则此保证无效。特别是, memory_order_seq_cst围栏确保仅针对围栏的总订单 他们自己。 通常,挡板不能用于恢复顺序 具有较弱订购规范的原子操作的一致性。 - 结束说明]
如何映射到汇编程序:
<强>案例-1:强>
atomic<int> x, y
y.store(1, memory_order_relaxed); //(1)
atomic_thread_fence(memory_order_seq_cst); //(2)
x.load(memory_order_relaxed); //(3)
此代码 总是等同于Case-2的含义,但此代码在STORE&amp;之间产生相同的指令。 LOAD,以及LOAD和STORE都使用memory_order_seq_cst
- 这是顺序一致性,阻止StoreLoad重新排序,案例-2 :
atomic<int> x, y;
y.store(1, memory_order_seq_cst); //(1)
x.load(memory_order_seq_cst); //(3)
有一些注意事项:
或者可以使用其他说明形式的类似操作:
LOCK
- 前缀将Store-Buffer与MFENCE
完全一致,以防止StoreLoad重新排序DMB ISH
是完全屏障,可以阻止StoreLoad重新排序:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/CHDGACJD.html ARMv8-A指南
表13.1。屏障参数
ISH
任意 - 任何Any - Any这意味着加载和存储必须在之前完成 障碍。屏障后出现的加载和存储 程序订单必须等待屏障完成。
可以通过这两个指令之间的附加指令来防止重新排序两条指令。当我们看到第一个STORE(seq_cst)和下一个LOAD(seq_cst)之间生成的指令与FENCE(seq_cst)相同(atomic_thread_fence(memory_order_seq_cst)
)
将C / C ++ 11 memory_order_seq_cst
映射到不同的CPU架构:load()
,store()
,atomic_thread_fence()
:
注意atomic_thread_fence(memory_order_seq_cst);
始终生成全屏障
x86_64:商店 - MOV (into memory),
MFENCE
,加载 - MOV (from memory)
,围栏 - MFENCE
x86_64-alt:商店 - MOV (into memory)
,LOAD- MFENCE
,MOV (from memory)
,围栏 - MFENCE
x86_64-alt3:商店 - (LOCK) XCHG
,负载 - MOV (from memory)
,围栏 - MFENCE
- 完全屏障
x86_64-alt4:商店 - MOV (into memory)
,负载 - LOCK XADD(0)
,围栏 - MFENCE
- 全屏障
PowerPC:商店 - hwsync; st
,加载 - hwsync;
ld; cmp; bc; isync
,围栏 - hwsync
Itanium:STORE - st.rel;
mf
,LOAD - ld.acq
,fence - mf
ARMv7:商店 - dmb ish; str;
dmb ish
,加载 - ldr; dmb ish
,栅栏 - dmb ish
ARMv7-alt:STORE - dmb ish; str
,LOAD- dmb ish;
ldr; dmb ish
,围栏 - dmb ish
ARMv8(AArch32):商店 - STL
,负载 - LDA
,围栏 - DMB ISH
- 全屏障
ARMv8(AArch64):商店 - STLR
,负载 - LDAR
,围栏 - DMB ISH
- 完全屏障
MIPS64:商店 - sync; sw;
sync;
,加载 - sync; lw; sync;
,围栏 - sync
描述了C / C ++ 11语义到不同CPU架构的所有映射:load(),store(),atomic_thread_fence():http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
由于顺序一致性会阻止StoreLoad重新排序,并且由于顺序一致性(store(memory_order_seq_cst)
和下一个load(memory_order_seq_cst)
)生成的指令与atomic_thread_fence(memory_order_seq_cst)
相同,因此{{1}阻止StoreLoad重新排序。
答案 1 :(得分:0)
C ++ fences不是CPU fence指令的直接等价物,尽管它们可能就是这样实现的。 C ++ fences是C ++内存模型的一部分,它完全是关于可见性和排序约束的。
鉴于处理器通常会对读取和写入进行重新排序,并在将值提供给其他核心或处理器之前将其缓存在本地,因此其他处理器可以看到效果的顺序通常是不可预测的。
在考虑这些语义时,重要的是要考虑一下你试图阻止的内容。
假设代码映射到机器指令,如(1),然后(2)然后(3),这些指令保证(1)在执行(3)之前全局可见。
该片段的整个目的是与另一个线程进行通信。在此代码段在我们的处理器上执行时,您无法保证其他线程在任何处理器上运行。因此,整个片段可以不间断地运行,并且(3)在执行(1)时仍将读取x
中的任何值。在这种情况下,它与(3)(1)(2)的执行顺序无法区分。
所以:是的,这是一个允许的优化,因为你无法分辨出来。
答案 2 :(得分:0)
根据赫伯·萨特(Herb Sutter)的talk(请参见时间45:00),std::memory_order_seq_cst
将强制执行StoreLoad,与std::memory_order_acq_rel
不同。