C++ std::memory\u order\u XXX的工作原理

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

我不明白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_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期望不同的内存模式在汇编代码上有不同的实现
但是设置不同的模式值对汇编没有影响,谁能解释这一点呢?

每个内存模型设置都有其语义。编译器有义务满足此语义,即:

  • 它不允许编译器执行某些优化,例如读取和写入的重新排序

  • 它指示编译器将完全相同的消息传播到硬件。如何做到这一点,取决于平台。x86_64本身提供了非常强大的内存模型。因此,在几乎所有情况下,无论您选择何种内存模型,您都不会看到为x86_64生成的汇编代码有什么不同。然而,在RISC架构(例如ARM)上,您会看到不同之处,因为编译器必须插入内存屏障。内存屏障的类型取决于选定的内存模型设置

  • 编辑:看一看。它非常古老,是关于Java的,但它从编译器的角度对内存模型提供了我所知道的最好的解释。特别是,请查看不同体系结构的内存屏障说明表。

    给定代码:

    #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中当前的代码生成中,它将涉及原子的每个语句编译为自己的语句。好的做法是对每个语句使用不同的函数


    C++,爪哇> /c++比较:Java易失性语义较强,然后发布C++ C++ OPS。也没有C++的等价物。
    test1():
            movq    $41, gt(%rip)
            movq    $42, gt(%rip)
            movq    gt(%rip), %rax
            movq    gt(%rip), %rax
            ret