some_atomic.load(std :: memory_order_acquire)只是一直到 一个简单的加载指令,和 some_atomic.store(std :: memory_order_release)简单到了 商店指导。
众所周知,在 x86 上,操作load()
和store()
内存障碍memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel
不需要处理器指令。
但在 ARMv8 上,我们知道load()
和store()
存在以下内存障碍:
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2
关于CPU的不同架构:http://g.oswego.edu/dl/jmm/cookbook.html
接下来,但对于 x86 上的CAS操作,具有不同内存屏障的这两行在反汇编代码中是相同的( MSVS2012 x86_64 ):
a.compare_exchange_weak(temp, 4, std::memory_order_seq_cst, std::memory_order_seq_cst);
000000013FE71A2D mov ebx,dword ptr [temp]
000000013FE71A31 mov eax,ebx
000000013FE71A33 mov ecx,4
000000013FE71A38 lock cmpxchg dword ptr [temp],ecx
a.compare_exchange_weak(temp, 5, std::memory_order_relaxed, std::memory_order_relaxed);
000000013FE71A4D mov ecx,5
000000013FE71A52 mov eax,ebx
000000013FE71A54 lock cmpxchg dword ptr [temp],ecx
GCC 4.8.1 x86_64 - GDB 编译的反汇编代码:
a.compare_exchange_weak(temp, 4, std::memory_order_seq_cst, std::memory_order_seq_cst);
a.compare_exchange_weak(temp, 5, std::memory_order_relaxed, std::memory_order_relaxed);
0x4613b7 <+0x0027> mov 0x2c(%rsp),%eax
0x4613bb <+0x002b> mov $0x4,%edx
0x4613c0 <+0x0030> lock cmpxchg %edx,0x20(%rsp)
0x4613c6 <+0x0036> mov %eax,0x2c(%rsp)
0x4613ca <+0x003a> lock cmpxchg %edx,0x20(%rsp)
在x86 / x86_64平台上是否有任何原子CAS操作,像atomic_val.compare_exchange_weak(temp, 1, std::memory_order_relaxed, std::memory_order_relaxed);
这样的例子总是满足于排序std::memory_order_seq_cst
?
如果x86上的任何CAS操作始终以顺序一致性(std::memory_order_seq_cst
)运行而不考虑障碍,那么在ARMv8上它是一样的吗?
问题: std::memory_order_relaxed
CAS
的顺序是否应阻止x86或ARM上的内存总线?
答案: x86任何compare_exchange_weak()
操作与任何std::memory_orders
(偶数std::memory_order_relaxed
)始终转换为LOCK CMPXCHG
with lock bus, to be really atomic,XCHG
- "the cmpxchg
is just as expensive as the xchg
instruction"的费用相同。
(添加:XCHG
等于LOCK XCHG
,但CMPXCHG
不等于LOCK CMPXCHG
(这实际上是原子的)
对于任何`compare_exchange_weak()的 ARM和PowerPC,对于不同的std :: memory_orders,是不同的锁处理器指令,通过LL/SC。
x86(CAS除外),ARM和PowerPC的处理器内存屏障指令:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
答案 0 :(得分:5)
您不应该担心编译器将给定C11构造映射到哪些指令,因为这不会捕获所有内容。相反,您需要开发有关C11内存模型保证的代码。如上面的注释所述,只要不违反C11内存模型,您的编译器或未来的编译器就可以自由地重新排序宽松的内存操作。通过像CDSChecker这样的工具运行代码也是值得的,看看内存模型下允许的行为。
答案 1 :(得分:1)
x86保证订购负载后的负载,并订购后续存储的存储。鉴于CAS需要加载和存储,所有操作都必须在它周围进行排序。
但是,值得注意的是,在存在多个带有memory_order_relaxed的原子的情况下,允许编译器对它们进行重新排序。使用memory_order_seq_cst不能这样做。
答案 2 :(得分:1)
我认为编译器即使对lock cmpxchg
也会发出memory_order_relaxed
,因为这是确保compare + exchange本身实际上是原子的唯一方法。就像artless_noise在评论中所说,其他架构可以使用Load Linked / Store Conditional来实现compare_exchange_weak(...)
。
memory_order_relaxed
仍然应该让编译器将其他变量的存储从循环中提升出来,否则在编译时重新排序内存访问。
如果有一种方法可以在x86上执行它,这也不是一个完整的内存屏障,一个好的编译器会将它用于memory_order_relaxed
。