4

正如安东尼威廉姆斯所说

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 上它是一样的吗?

问题: x86 或 ARM 上std::memory_order_relaxed的块内存总线的顺序应该是什么?CAS

回答:x86 上,任何compare_exchange_weak()带有 any std::memory_orders(even std::memory_order_relaxed)的操作总是转换为LOCK CMPXCHG 带有锁总线的,真正原子的,并且具有与XCHG- “thecmpxchgxchg指令一样昂贵同等成本。

(加法:XCHG等于LOCK XCHG,但CMPXCHG不等于LOCK CMPXCHG(这真的是原子的)

ARM 和 PowerPC 上,任何`compare_exchange_weak()对于不同的 std::memory_orders 都有不同的锁处理器指令,通过LL/SC

x86(CAS 除外)、ARM 和 PowerPC 的处理器内存屏障指令:http: //www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

4

3 回答 3

5

您不必担心编译器将给定的 C11 构造映射到哪些指令,因为这不会捕获所有内容。相反,您需要根据 C11 内存模型的保证来开发代码。正如上面的注释所指出的,只要不违反 C11 内存模型,您的编译器或未来的编译器可以自由地重新排序宽松的内存操作。通过 CDSChecker 之类的工具运行代码以查看内存模型下允许哪些行为也是值得的。

于 2013-09-03T05:46:53.073 回答
2

x86 保证加载之后的加载是有序的,存储之后的存储是有序的。鉴于 CAS 需要加载和存储,所有操作都必须围绕它进行排序。

然而,值得注意的是,在存在多个具有 memory_order_relaxed 的原子时,允许编译器重新排序它们。它不能用 memory_order_seq_cst 这样做。

于 2013-09-03T05:05:04.090 回答
1

我认为编译器lock cmpxchg甚至会发出 formemory_order_relaxed因为这是确保 compare+exchange 本身实际上是原子的唯一方法。就像评论中所说的 artless_noise 一样,其他架构可以使用Load Linked / Store Conditional来实现compare_exchange_weak(...)

memory_order_relaxed仍然应该让编译器将其他变量的存储提升出循环,否则在编译时重新排序内存访问。

如果有一种方法可以在 x86 上做到这一点,这也不是一个完整的内存屏障,一个好的编译器会将它用于memory_order_relaxed.

于 2015-09-04T08:00:25.983 回答