gpt4 book ai didi

C++ std::memory_order_relaxed 困惑

转载 作者:行者123 更新时间:2023-12-03 06:51:58 25 4
gpt4 key购买 nike

我在看 this article来自 GCC Wiki 关于 C++ 内存屏障(及其很棒的)。
在我到达这一点之前,它非常简单:
相反的方法是 std::memory_order_relaxed。该模型通过消除发生之前的限制,允许更少的同步。这些类型的原子操作也可以对它们执行各种优化,例如删除死存储和共用。
所以在前面的例子中:

-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 */
由于线程不需要跨系统同步,因此本示例中的任一断言实际上都可能失败。
好的,这也很简单,让我们继续..
-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)
断言不能失败。一旦线程 2 看到 2 的存储,它就不能再看到值 1。这可以防止将一个变量的松弛加载与可能别名的不同引用的松弛加载合并。
这让我很困惑,为什么 y 不能加载值 2 而 z 加载值 1(并导致断言失败),因为排序在线程 1 中不同步?

最佳答案

宽松的排序是相对于其他内存访问的操作顺序而言的,而不是相对于被松弛修改的原子的排序。在您的第一种情况下,您可以在 x 中看到 10 的事实。对 y 的值没有任何意义.反之亦然。
但是你的第二种情况不同,因为它影响同一个原子对象。
[intro.races]/10告诉我们,在一个线程中,如果一个操作在另一个之前被排序,那么该操作“发生在”另一个之前。和 [intro.races]/14-17 outline the following behavior with regard to atomics :

The four preceding coherence requirements effectively disallow compiler reordering of atomic operations to a single object, even if both operations are relaxed loads.


这就是你在这里所拥有的。所有的修改都发生在同一个对象上,所以它们必须以某种顺序发生。即使无法准确确定该顺序,该顺序也必须尊重代码的“先发生”关系。
线程 1 的两个操作按“先发生”关系排序。并且线程 2 的操作本身是由“发生在之前”关系排序的。
由于它们都作用于同一个原子对象,如果 y得到 2 的值,那么它一定是“发生在”之后 x被设置为 2。所以 x 的访问顺序一定是“x = 1,x = 2,读取x”。自从上次阅读 x 以来发生在第一次读取 x 之后,它得到的值不能为 1。

关于C++ std::memory_order_relaxed 困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64311845/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com