【问题标题】:C++0x: memory orderingC++0x:内存排序
【发布时间】:2010-05-26 11:54:30
【问题描述】:

当前C++0x draft 在第 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 之前(因此也发生在之前)排序的。这会创建一个我认为不允许的循环发生之前的关系。

【问题讨论】:

  • 我更改了标题,因为问题本身与投机商店无关。对于投机商店,请参阅stackoverflow.com/questions/2001913/…
  • 存储推测是这里的关键字,因为结果r1=r2=1 要求在两次读取之前对存储进行重新排序(“推测”)。你的标题太模糊了。
  • C++0x 工作论文上下文中的推测存储指的是编译器推测,请参阅我在之前的评论中链接到的问题。您的问题与硬件所做的重新排序有关(取决于硬件架构实现的共享内存一致性模型),以及 C++0x 如何通过发出各种内存屏障指令来提供约束此内存重新排序的设施。因此我觉得我提供的标题比原来的更合适;但是,嘿,这是您的问题,所以请随意将其更改为您想要的任何内容。

标签: c++ c++11 memory-model


【解决方案1】:

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

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

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

acquire
// other stuff
release

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

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

【讨论】:

  • 我不确定我是否理解您的回答。
  • 嗯,我的澄清有帮助吗?如果没有,具体有什么不明白的?
  • 举我的第二个例子,用放松替换发布,获取保持获取。 r1=r2=1 可能吗?现在再次从第二个示例的初始版本重新启动,但这次替换获取方式为放松并保持版本不变。 r1=r2=1 可能吗?
  • 嗯,我认为在第二个示例中,每个线程只需要限制其中一项操作,以防止 r1=r2=1。在一个更复杂的示例中,您可能两者都需要,因为在获取/释放对之间有一些不允许“泄漏”的东西。然而,更一般地说,任何超出默认顺序一致性语义的东西最好留给正在开发高性能锁定机制或无锁算法的专家,然后普通人可以使用。
  • 我不是凡人 :-) 感谢您的澄清。
猜你喜欢
  • 2017-01-26
  • 2012-09-09
  • 1970-01-01
  • 2020-09-22
  • 2020-01-06
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多