5

当前的C++0x 草案在第 29.3.9 节和第 29.3.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);

结果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);

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

4

1 回答 1

4

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

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

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

acquire
// other stuff
release

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

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

于 2010-05-26T12:35:49.303 回答