c++ - gcc-c++ 是否没有为当前的 x86-64 处理器优化原子操作

标签 c++ assembly concurrency x86-64 atomic

给定以下测试程序:

#include <atomic>
#include <iostream>

int64_t process_one() {
        int64_t a;
        //Should be atomic on my haswell
        int64_t assign = 42;
        a = assign;
        return a;
}

int64_t process_two() {
        std::atomic<int64_t> a;
        int64_t assign = 42;
        a = assign;
        return a;
}

int main() {
        auto res_one = process_one();
        auto res_two = process_two();
        std::cout << res_one << std::endl;
        std::cout << res_two << std::endl;
}

编译:

g++ --std=c++17 -O3 -march=native main.cpp

代码为这两个函数生成了以下汇编:

00000000004007c0 <_Z11process_onev>:
  4007c0:       b8 2a 00 00 00          mov    $0x2a,%eax
  4007c5:       c3                      retq
  4007c6:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4007cd:       00 00 00

00000000004007d0 <_Z11process_twov>:
  4007d0:       48 c7 44 24 f8 2a 00    movq   $0x2a,-0x8(%rsp)
  4007d7:       00 00
  4007d9:       0f ae f0                mfence
  4007dc:       48 8b 44 24 f8          mov    -0x8(%rsp),%rax
  4007e1:       c3                      retq
  4007e2:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4007e9:       00 00 00
  4007ec:       0f 1f 40 00             nopl   0x0(%rax)

就我个人而言,我不太会说汇编程序,但(我在这里可能弄错了)似乎 process_two 编译为包含所有 process_one,然后包含一些。

然而,据我所知,“现代”x86-64 处理器(例如 Haswell,我在其上编译了这个)将自动赋值而不需要任何额外的操作(在这种情况下,我相信额外的操作是process_two 中的 mfence 指令)。

那么为什么 gcc 不优化进程二中的代码以使其与进程一完全一样呢?鉴于我编译时使用的标志。

是否仍然存在原子存储的行为不同于对普通变量赋值的情况,因为它们都是 8 字节。

最佳答案

原因是 std::atomic 的默认使用也意味着内存顺序

std::memory_order order = std::memory_order_seq_cst

为了实现这种一致性,编译器必须告诉处理器不要对指令重新排序。它通过使用 mfence 指令来实现。

改变你的

    a = assign;

    a.store(assign, std::memory_order_relaxed);

你的输出将从

process_two():
        mov     QWORD PTR [rsp-8], 42
        mfence
        mov     rax, QWORD PTR [rsp-8]
        ret

process_two():
        mov     QWORD PTR [rsp-8], 42
        mov     rax, QWORD PTR [rsp-8]
        ret

正如您所期望的那样。

关于c++ - gcc-c++ 是否没有为当前的 x86-64 处理器优化原子操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45210214/

相关文章:

java - 信号量和条件的区别(ReentrantLock)

c++ - Boost Property Tree Json 读取包含 LPWSTR 的文件

python - 在python中按用户计算并发 session

c++ - 使用按位运算符检查数字是正数还是负数

assembly - mips 组件的字符串长度

assembly - ASM 8086 中的 ADC 指令

assembly - 如何检查emu8086中CF标志是否为1?

java - 为什么我的多线程 Java 程序没有最大化我机器上的所有内核?

c++ - Boost XML - 获取下一个节点

c++ - 图像 (PNG) 不显示在 C++ Win32 项目的最终 exe 中