C++ std::memory\u order\u XXX的工作原理
我不明白std::memory\u order\u XXX(比如memory\u order\u release/memory\u order\u acquire…)是如何工作的 从一些文档中可以看出,这些内存模式有不同的功能,但我真的很困惑,它们有相同的汇编代码,是什么决定了这些差异 该守则:C++ std::memory\u order\u XXX的工作原理,c++,c++11,x86,memory-barriers,memory-model,C++,C++11,X86,Memory Barriers,Memory Model,我不明白std::memory\u order\u XXX(比如memory\u order\u release/memory\u order\u acquire…)是如何工作的 从一些文档中可以看出,这些内存模式有不同的功能,但我真的很困惑,它们有相同的汇编代码,是什么决定了这些差异 该守则: static std::atomic<long> gt; void test1() { gt.store(1, std::memory_order_re
static std::atomic<long> gt;
void test1() {
gt.store(1, std::memory_order_release);
gt.store(2, std::memory_order_relaxed);
gt.load(std::memory_order_acquire);
gt.load(std::memory_order_relaxed);
}
static std::atomic gt;
void test1(){
gt.存储(1,标准::内存\订单\发布);
gt.存储(2,标准::内存\u顺序\u松弛);
gt.加载(标准::内存\u顺序\u获取);
gt.加载(标准::内存\u顺序\u松弛);
}
对应于:
00000000000007a0 <_Z5test1v>:
7a0: 55 push %rbp
7a1: 48 89 e5 mov %rsp,%rbp
7a4: 48 83 ec 30 sub $0x30,%rsp
**memory_order_release:
7a8: 48 c7 45 f8 01 00 00 movq $0x1,-0x8(%rbp)
7af: 00
7b0: c7 45 e8 03 00 00 00 movl $0x3,-0x18(%rbp)
7b7: 8b 45 e8 mov -0x18(%rbp),%eax
7ba: be ff ff 00 00 mov $0xffff,%esi
7bf: 89 c7 mov %eax,%edi
7c1: e8 b1 00 00 00 callq 877 <_ZStanSt12memory_orderSt23__memory_order_modifier>
7c6: 89 45 ec mov %eax,-0x14(%rbp)
7c9: 48 8b 55 f8 mov -0x8(%rbp),%rdx
7cd: 48 8d 05 44 08 20 00 lea 0x200844(%rip),%rax # 201018 <_ZL2gt>
7d4: 48 89 10 mov %rdx,(%rax)
7d7: 0f ae f0 mfence**
**memory_order_relaxed:
7da: 48 c7 45 f0 02 00 00 movq $0x2,-0x10(%rbp)
7e1: 00
7e2: c7 45 e0 00 00 00 00 movl $0x0,-0x20(%rbp)
7e9: 8b 45 e0 mov -0x20(%rbp),%eax
7ec: be ff ff 00 00 mov $0xffff,%esi
7f1: 89 c7 mov %eax,%edi
7f3: e8 7f 00 00 00 callq 877 <_ZStanSt12memory_orderSt23__memory_order_modifier>
7f8: 89 45 e4 mov %eax,-0x1c(%rbp)
7fb: 48 8b 55 f0 mov -0x10(%rbp),%rdx
7ff: 48 8d 05 12 08 20 00 lea 0x200812(%rip),%rax # 201018 <_ZL2gt>
806: 48 89 10 mov %rdx,(%rax)
809: 0f ae f0 mfence**
**memory_order_acquire:
80c: c7 45 d8 02 00 00 00 movl $0x2,-0x28(%rbp)
813: 8b 45 d8 mov -0x28(%rbp),%eax
816: be ff ff 00 00 mov $0xffff,%esi
81b: 89 c7 mov %eax,%edi
81d: e8 55 00 00 00 callq 877 <_ZStanSt12memory_orderSt23__memory_order_modifier>
822: 89 45 dc mov %eax,-0x24(%rbp)
825: 48 8d 05 ec 07 20 00 lea 0x2007ec(%rip),%rax # 201018 <_ZL2gt>
82c: 48 8b 00 mov (%rax),%rax**
**memory_order_relaxed:
82f: c7 45 d0 00 00 00 00 movl $0x0,-0x30(%rbp)
836: 8b 45 d0 mov -0x30(%rbp),%eax
839: be ff ff 00 00 mov $0xffff,%esi
83e: 89 c7 mov %eax,%edi
840: e8 32 00 00 00 callq 877 <_ZStanSt12memory_orderSt23__memory_order_modifier>
845: 89 45 d4 mov %eax,-0x2c(%rbp)
848: 48 8d 05 c9 07 20 00 lea 0x2007c9(%rip),%rax # 201018 <_ZL2gt>
84f: 48 8b 00 mov (%rax),%rax**
852: 90 nop
853: c9 leaveq
854: c3 retq
00000000000008cc <_ZStanSt12memory_orderSt23__memory_order_modifier>:
8cc: 55 push %rbp
8cd: 48 89 e5 mov %rsp,%rbp
8d0: 89 7d fc mov %edi,-0x4(%rbp)
8d3: 89 75 f8 mov %esi,-0x8(%rbp)
8d6: 8b 55 fc mov -0x4(%rbp),%edx
8d9: 8b 45 f8 mov -0x8(%rbp),%eax
8dc: 21 d0 and %edx,%eax
8de: 5d pop %rbp
8df: c3 retq
0000000000000 7a0:
7a0:55%按需付费
7a1:48 89 e5 mov%rsp,%rbp
7a4:48 83 ec 30分$0x30,%rsp
**内存\u顺序\u释放:
7a8:48 c7 45 f8 01 00 movq$0x1,-0x8(%rbp)
7af:00
7b0:c7 45 e8 03 00移动$0x3,-0x18(%rbp)
7b7:8B45E8MOV-0x18(%rbp),%eax
7ba:be ff ff 00 mov$0xffff,%esi
7bf:89 c7 mov%eax,%edi
7c1:e8 b1 00 00 00呼叫877
7c6:89 45 ec mov%eax,-0x14(%rbp)
7c9:48 8b 55 f8 mov-0x8(%rbp),%rdx
7cd:48 8d 05 44 08 20 00 lea 0x200844(%rip),%rax#201018
7d4:488910MOV%rdx,(%rax)
7d7:0f ae f0 mfence**
**内存\u顺序\u松弛:
7da:48 c7 45 f0 02 00 movq$0x2,-0x10(%rbp)
7e1:00
7e2:c7 45 e0 00动产$0x0,-0x20(%rbp)
7e9:8b 45 e0 mov-0x20(%rbp),%eax
7ec:be ff ff 00 mov$0xffff,%esi
7f1:89 c7 mov%eax,%edi
7f3:e8 7f 00 00呼叫877
7f8:89 45 e4 mov%eax,-0x1c(%rbp)
7fb:48 8b 55 f0 mov-0x10(%rbp),%rdx
7ff:48 8d 05 12 08 20 00 lea 0x200812(%rip),%rax#201018
806:488910MOV%rdx,(%rax)
809:0f ae f0 mfence**
**内存\u顺序\u获取:
80c:c7 45 d8 02 00动产$0x2,-0x28(%rbp)
813:8b 45 d8 mov-0x28(%rbp),%eax
816:be FFFF 00 mov$0xffff,%esi
81b:89 c7 mov%eax%edi
81d:e8 55 00 00 callq 877
822:89 45 dc mov%eax,-0x24(%rbp)
825:48 8d 05 ec 07 20 00 lea 0x2007ec(%rip),%rax#201018
82c:4880亿mov(%rax),%rax**
**内存\u顺序\u松弛:
82f:c7 45 D000动产$0x0,-0x30(%rbp)
836:8b 45 d0 mov-0x30(%rbp),%eax
839:be FFFF 00 mov$0xffff,%esi
83e:89 c7 mov%eax%edi
840:e8 32 00 00 callq 877
845:89 45 d4 mov%eax,-0x2c(%rbp)
848:48 8d 05 c9 07 20 00 lea 0x2007c9(%rip),%rax#201018
84f:4880亿mov(%rax),%rax**
852:90不
853:c9-Q
854:c3 retq
0000000000000 8cc:
8cc:55%rbp
8cd:48 89 e5 mov%rsp,%rbp
8d0:89 7d fc mov%edi,-0x4(%rbp)
8d3:89 75 f8移动%esi,-0x8(%rbp)
8d6:8b 55 fc mov-0x4(%rbp),%edx
8d9:8b 45 f8 mov-0x8(%rbp),%eax
8dc:21 d0和%edx,%eax
8de:5d pop%rbp
8df:c3 retq
I期望不同的内存模式在汇编代码上有不同的实现,
但是设置不同的模式值对汇编没有影响,谁能解释这一点呢?每个内存模型设置都有其语义。编译器有义务满足此语义,即:
#include <atomic>
static std::atomic<long> gt;
void test1() {
gt.store(41, std::memory_order_release);
gt.store(42, std::memory_order_relaxed);
gt.load(std::memory_order_acquire);
gt.load(std::memory_order_relaxed);
}
我们看到,为不同的内存顺序生成了完全相同的代码;虽然在同一函数中顺序测试不同指令是非常糟糕的做法,因为C++指令不必独立编译,上下文可能影响代码生成。但在GCC中当前的代码生成中,它将涉及原子的每个语句编译为自己的语句。好的做法是对每个语句使用不同的函数
test1():
movq $41, gt(%rip)
movq $42, gt(%rip)
movq gt(%rip), %rax
movq gt(%rip), %rax
ret