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

2022-01-06 00:00:00 gcc multithreading c++ c++11 x86

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

Here are four approaches to make Sequential Consistency in 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.英国/~pes20/cpp/cpp0xmappings.html

C/C++11 操作 x86 实现

C/C++11 Operation x86 implementation

  • 加载 Seq_Cst:MOV(从内存中)
  • Store Seq Cst: (LOCK) XCHG//替代方案:MOV(进入内存),MFENCE

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

Note: there is an alternative mapping of C/C++11 to x86, which instead of locking (or fencing) the Seq Cst store locks/fences the Seq Cst load:

  • 加载 Seq_Cst:LOCK XADD(0)//替代:MFENCE,MOV(从内存中)
  • 存储 Seq Cst:MOV(到内存中)

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

GCC 4.8.2(GDB in x86_64) uses first(1) approach for C++11-std::memory_order_seq_cst, i.e. LOAD(without fence) and 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

As we know, that MFENCE = LFENCE+SFENCE. Then this code we can rewrite to this: 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 唯一的重新排序(对于正常内存访问)是它可以潜在地重新排序跟随存储的加载.

The only reordering x86 does (for normal memory accesses) is that it can potentially reorder a load that follows a store.

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

SFENCE guarantees that all stores before the fence complete before all stores after the fence. LFENCE guarantees that all loads before the fence complete before all loads after the fence. For normal memory accesses, the ordering guarantees of individual SFENCE or LFENCE operations are already provided by default. Basically, LFENCE and SFENCE by themselves are only useful for the weaker memory access modes of x86.

LFENCE、SFENCE 或 LFENCE + SFENCE 都不会阻止重新排序后跟加载的存储.MFENCE 有.

Neither LFENCE, SFENCE, nor LFENCE + SFENCE prevents a store followed by a load from being reordered. MFENCE does.

相关参考是 Intel x86 架构手册.

The relevant reference is the Intel x86 architectural manual.

相关文章