简体   繁体   English

C++ std::memory_order_relaxed 混乱

[英]C++ std::memory_order_relaxed confusion

I was reading this article from GCC Wiki about C++ memory barriers (and its awesome).我正在阅读 GCC Wiki 上关于 C++ 内存障碍(及其很棒)的这篇文章
It was pretty straightforward until I got to this point:在我到达这一点之前,它非常简单:

The opposite approach is std::memory_order_relaxed.相反的方法是 std::memory_order_relaxed。 This model allows for much less synchronization by removing the happens-before restrictions.该模型通过消除发生之前的限制,允许更少的同步。 These types of atomic operations can also have various optimizations performed on them, such as dead store removal and commoning.这些类型的原子操作也可以对它们执行各种优化,例如删除死存储和共用。 So in the earlier example:所以在前面的例子中:

-Thread 1-
y.store (20, memory_order_relaxed)
x.store (10, memory_order_relaxed)

-Thread 2-
if (x.load (memory_order_relaxed) == 10)
  {
    assert (y.load(memory_order_relaxed) == 20) /* assert A */
    y.store (10, memory_order_relaxed)
  }

-Thread 3-
if (y.load (memory_order_relaxed) == 10)
  assert (x.load(memory_order_relaxed) == 10) /* assert B */

Since threads don't need to be synchronized across the system, either assert in this example can actually FAIL.由于线程不需要跨系统同步,因此本示例中的任一断言实际上都可能失败。

Ok, this is straightforward as well, lets carry on..好的,这也很简单,让我们继续..

-Thread 1-
x.store (1, memory_order_relaxed)
x.store (2, memory_order_relaxed)

-Thread 2-
y = x.load (memory_order_relaxed)
z = x.load (memory_order_relaxed)
assert (y <= z)

The assert cannot fail.断言不能失败。 Once the store of 2 is seen by thread 2, it can no longer see the value 1. This prevents coalescing relaxed loads of one variable across relaxed loads of a different reference that might alias.一旦线程 2 看到 2 的存储,它就不能再看到值 1。这可以防止将一个变量的松弛加载与可能别名的不同引用的松弛加载合并。

This is what confused me, why y cannot load the value 2 and z load the value 1 (and cause assertion to fail), since the ordering is not synchronized in thread 1?这让我很困惑,为什么 y 不能加载值 2 而 z 加载值 1(并导致断言失败),因为排序在线程 1 中不同步?

Relaxed ordering is relative to the ordering of operations with regard to other memory accesses , not ordering relative to the atomic being relax-modified.松弛排序是相对于其他内存访问的操作顺序而言的,而不是相对于被松弛修改的原子的排序。 In your first case, the fact that you can see 10 in x doesn't mean anything with regard to the value of y .在您的第一种情况下,您可以在x中看到 10 这一事实对于y的值没有任何意义。 And vice-versa.反之亦然。

But your second case is different, because it's affecting the same atomic object.但是你的第二种情况不同,因为它影响同一个原子对象。

[intro.races]/10 tells us that, within a thread, if one operation is sequenced before another, then that operation "happens before" the other. [intro.races]/10告诉我们,在一个线程中,如果一个操作在另一个之前被排序,那么该操作“发生在”另一个之前。 And [intro.races]/14-17 outline the following behavior with regard to atomics : [intro.races]/14-17 概述了关于原子的以下行为

The four preceding coherence requirements effectively disallow compiler reordering of atomic operations to a single object, even if both operations are relaxed loads.前面的四个一致性要求有效地禁止编译器将原子操作重新排序为单个对象,即使这两个操作都是宽松加载。

And that's what you have here.这就是你在这里所拥有的。 All of the modifications are happening to the same object, so they must happen in some order.所有的修改都发生在同一个对象上,所以它们必须以某种顺序发生。 Even if that order cannot be determined exactly, the order must respect the "happens before" relationships of the code.即使无法准确确定该顺序,该顺序也必须尊重代码的“先发生”关系。

Thread 1's two operations are ordered by a "happens before" relationship.线程 1 的两个操作按“先发生”关系排序。 And Thread 2's operations are themselves ordered by a "happens before" relationship.并且线程 2 的操作本身是由“发生在之前”关系排序的。

Since they're all acting on the same atomic object, if y gets the value of 2, then it must have "happened after" x was set to 2. So the order of access for x must have been "x = 1, x = 2, read x".由于它们都作用于同一个原子对象,如果y的值是 2,那么它一定是“发生在” x被设置为 2 之后。所以x的访问顺序一定是“x = 1, x = 2,读取 x"。 And since the last read of x happens after the first read of x , the value it gets cannot be 1.由于最后一次读取x发生在第一次读取x ,所以它得到的值不能为 1。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM