以下是在 x86/x86_64 中实现顺序一致性的四种方法:
- LOAD(不带围栏)和 STORE+MFENCE
- LOAD(无栅栏)和LOCK XCHG
- MFENCE+LOAD 和 STORE(无栅栏)
- LOCK XADD(0) 和 STORE(无栅栏)
正如这里所写:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
C/C++11 Operation x86 implementation
- Load Seq_Cst: MOV (from memory)
- Store Seq Cst: (LOCK) XCHG // alternative: MOV (into memory),MFENCE
注意:有一个 C/C++11 到 x86 的替代映射,而不是锁定(或隔离) Seq Cst 存储锁定/隔离 Seq Cst 负载:
- Load Seq_Cst: LOCK XADD(0) // alternative: MFENCE,MOV (from memory)
- Store Seq Cst: MOV (into memory)
GCC 4.8.2(x86_64 中的 GDB) 对 C++11-std::memory_order_seq_cst 使用 first(1) 方法, 即 LOAD(无栅栏) 和 STORE+MFENCE:
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
我们知道,MFENCE = LFENCE+SFENCE。然后这段代码我们可以改写成这样:LOAD(without fence) and STORE+LFENCE+SFENCE
问题:
- 为什么我们这里不需要在 LOAD 之前使用 LFENCE,而需要在 STORE 之后使用 LFENCE(因为 LFENCE 只有在 LOAD 之前才有意义!)?
- 为什么 GCC 不使用 std::memory_order_seq_cst 的方法:LOAD(无围栏)和 STORE+SFENCE?
最佳答案
x86 唯一的重新排序(对于正常的内存访问)是它可能会重新排序存储之后的加载。
SFENCE 保证围墙前的所有店铺在围墙后的所有店铺之前完成。 LFENCE 保证围栏之前的所有负载在围栏之后的所有负载之前完成。对于正常的内存访问,默认情况下已经提供了单个 SFENCE 或 LFENCE 操作的排序保证。基本上,LFENCE 和 SFENCE 本身只对 x86 较弱的内存访问模式有用。
无论是 LFENCE、SFENCE 还是 LFENCE + SFENCE 都不能防止加载后的存储被重新排序。 MFENCE 可以。
相关引用资料是 Intel x86 架构手册。
关于c++ - 为什么 GCC 不使用 LOAD(无围栏)和 STORE+SFENCE 来实现顺序一致性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19047327/