c++ - 为什么 GCC 不使用 LOAD(无围栏)和 STORE+SFENCE 来实现顺序一致性?

标签 c++ multithreading gcc c++11 x86

以下是在 x86/x86_64 中实现顺序一致性的四种方法:

  1. LOAD(不带围栏)和 STORE+MFENCE
  2. LOAD(无栅栏)和LOCK XCHG
  3. MFENCE+LOAD 和 STORE(无栅栏)
  4. LOCK XADD(0) 和 STORE(无栅栏)

正如这里所写:http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

C/C++11 Operation x86 implementation

  • Load Seq_Cst: MOV (from memory)
  • Store Seq Cst: (LOCK) XCHG // alternative: MOV (into memory),MFENCE

注意:有一个 C/C++11 到 x86 的替代映射,而不是锁定(或隔离) Seq Cst 存储锁定/隔离 Seq Cst 负载:

  • Load Seq_Cst: LOCK XADD(0) // alternative: MFENCE,MOV (from memory)
  • Store Seq Cst: MOV (into memory)

GCC 4.8.2(x86_64 中的 GDB)C++11-std::memory_order_seq_cst 使用 first(1) 方法, 即 LOAD(无栅栏) 和 STORE+MFENCE:

std::atomic<int> a;
int temp = 0;
a.store(temp, std::memory_order_seq_cst);
0x4613e8  <+0x0058>         mov    0x38(%rsp),%eax
0x4613ec  <+0x005c>         mov    %eax,0x20(%rsp)
0x4613f0  <+0x0060>         mfence

我们知道,MFENCE = LFENCE+SFENCE。然后这段代码我们可以改写成这样:LOAD(without fence) and STORE+LFENCE+SFENCE

问题:

  1. 为什么我们这里不需要在 LOAD 之前使用 LFENCE,而需要在 STORE 之后使用 LFENCE(因为 LFENCE 只有在 LOAD 之前才有意义!)?
  2. 为什么 GCC 不使用 std::memory_order_seq_cst 的方法:LOAD(无围栏)和 STORE+SFENCE?

最佳答案

x86 唯一的重新排序(对于正常的内存访问)是它可能会重新排序存储之后的加载。

SFENCE 保证围墙前的所有店铺在围墙后的所有店铺之前完成。 LFENCE 保证围栏之前的所有负载在围栏之后的所有负载之前完成。对于正常的内存访问,默认情况下已经提供了单个 SFENCE 或 LFENCE 操作的排序保证。基本上,LFENCE 和 SFENCE 本身只对 x86 较弱的内存访问模式有用。

无论是 LFENCE、SFENCE 还是 LFENCE + SFENCE 都不能防止加载后的存储被重新排序。 MFENCE 可以。

相关引用资料是 Intel x86 架构手册。

关于c++ - 为什么 GCC 不使用 LOAD(无围栏)和 STORE+SFENCE 来实现顺序一致性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19047327/

相关文章:

c++ - 如何摆脱 Djinni 生成的不必要函数 - ToString (in Java)/Description (in Objc)?

c++ - 程序的参数格式有没有标准?

C++ shared_mutex 实现

multithreading - Scala 的阻塞上下文似乎不适用于混合阻塞/非阻塞作业。为什么?

linux - elf 文件自以为小,其实很大!无法生成 .bin 和 .hex 文件

c++ - 实现 Bailey-Borwein-Plouffe

java - 为什么主线程结束时 setdaemon 属性没有结束子线程?

c++ - 有没有办法弃用命名空间?

python - Cython fatal error : Python. h 没有这样的文件或目录

c++ - 我们可以依赖减少容量的技巧吗?