在Intel x86/x86_64系统有3种类型的内存屏障:l的,栅栏的和m的。在他们的使用方面的问题。对于顺序语义(SC)足以使用MOV[addr],reg MFENCE
对于所有需要SC-语义学的存储单元。然而,你可以写代码在整体上,反之亦然:MFENCE MOV reg,[addr]
。显然感觉到,如果存储到内存的数量通常少于它的负载,那么使用写屏障的总成本更低。在此基础上,我们必须使用顺序存储到内存,做了另一个优化-[LOCK]XCHG,这可能是更便宜的,由于这一事实,MFENCE内XCHG适用于仅在XCHG中使用的内存的缓存行(视频在0:28:20说MFENCE更昂贵的XCHG)。
http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
C/C 11操作x86实施
注意:有一个C/C 11到x86的替代映射,它不是锁定(或Geofence)Seq Cst存储锁定/GeofenceSeq Cst负载:
不同之处在于ARM和Power内存屏障仅与LLC(末级缓存)交互,而x86与较低级别的缓存L1/L2交互。在x86/x86_64中:
lgrid
:(CoreX-L1)-在ARM:
ldr; dmb;
:L3-C 11代码编译GCC4.8.2-GDBx86_64:
std::atomic<int> a;
int temp = 0;
a.store(temp, std::memory_order_seq_cst);
0x4613e8 <+0x0058> mov 0x38(%rsp),%eax
0x4613ec <+0x005c> mov %eax,0x20(%rsp)
0x4613f0 <+0x0060> mfence
但是为什么在x86/x86_64Sequential Semantic(SC)上使用通过MOV[addr],reg MFENCE
,而不是MOV[addr],reg SFENCE
,为什么我们需要全GeofenceMFENCE
而不是SFENCE
?
sgrid
不会阻止StoreLoad重新排序。除非有任何NT存储正在运行,否则在架构上是无操作的。存储已经等待旧存储提交,然后它们自己提交到L1d并变得全局可见,因为x86不允许StoreStore重新排序。(除了NT存储/存储到WC内存)
seq_cst您需要一个完整的屏障来刷新存储缓冲区/确保所有旧存储在以后加载之前都是全局可见的。请参阅https://preshing.com/20120515/memory-reordering-caught-in-the-act/示例,其中在实践中未能使用mgrid
会导致不顺序一致的行为,即内存重新排序。
正如你所发现的,可以在每个seq_cst负载上映射seq_cst到x86 asm,而不是在每个seq_cststore/RMW上。在这种情况下,你不需要商店上的任何屏障说明(所以他们会发布语义学),但是你需要在每个atomic::load(seq_cst)
之前使用mgrid
。
你不需要一个的栅栏
;的栅栏
确实足够了。事实上,在x86中你永远不需要的栅栏
,除非你正在处理一个设备。但是英特尔(我认为AMD)已经(或者至少已经)与的栅栏
和的栅栏
共享一个实现(即刷新存储缓冲区),所以使用较弱的栅栏
没有性能优势。
BTW,请注意,您不必在每次写入共享变量后刷新;您只需在不同共享变量的写入和后续读取之间进行刷新。