C++ 0x:内存排序

Gio*_*hal 5 c++ memory-model c++11

当前的C++ 0x草案在第29.3.9节和第293.10节,第1111-1112节中说明,在以下示例中:

// Thread 1
r1 = y.load(memory_order_relaxed);
x.store(1, memory_order_relaxed);

// Thread 2
r2 = x.load(memory_order_relaxed);
y.store(1, memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)

结果r1 = r2 = 1是可能的,因为每个线程的操作都是放松的,并且是不相关的地址.现在我的问题是关于以下(类似)示例的可能结果:

// Thread 1
r1 = y.load(memory_order_acquire);
x.store(1, memory_order_release);

// Thread 2
r2 = x.load(memory_order_acquire);
y.store(1, memory_order_release);
Run Code Online (Sandbox Code Playgroud)

我认为在这种情况下结果r1 = r2 = 1是不可能的.如果可能的话,y的负载将与商店同步(因此发生在之前).与x类似,x的加载将在商店到x之前发生.但是y的负载在存储到x之前(因此也发生在 - 之前)被排序.这创建了一个循环发生在之前的关系,我认为是不允许的.

jan*_*neb 4

如果我们花时间(或者指令序列,如果你喜欢的话)向下流动,就像阅读代码一样,那么我的理解是

  • 获取栅栏允许其他内存访问向下移动越过栅栏,但不能向上移动越过栅栏
  • 释放栅栏允许其他内存访问向上移动越过栅栏,但不能向下移动越过栅栏

换句话说,如果你有类似的代码

acquire
// other stuff
release
Run Code Online (Sandbox Code Playgroud)

那么内存访问可能会从获取/释放对的外部移动到内部,但反之则不然(并且它们也可能不会完全跳过获取/释放对)。

通过问题中第一个示例中宽松的一致性语义,硬件可以重新排序内存访问,以便存储在加载之前进入内存系统,从而允许 r1=r2=1。使用第二个示例中的获取/释放语义,可以防止重新排序,因此 r1=r2=1 是不可能的。