繁体   English   中英

C++ 原子获取/释放操作的实际含义

[英]C++ atomic acquire / release operations what it actually means

我正在浏览页面并试图了解 Memory model 同步模式。 在下面从那里提取的示例中:

 -Thread 1-       -Thread 2-
 y = 1            if (x.load() == 2)
 x.store (2);        assert (y == 1)

到哪个声明在线程 1 中存储到“y”之前发生到“x”的存储。这里的“y”变量是普通全局变量还是原子变量?

此外,如果线程 2 中 'x' 的加载获得线程 1 中发生的存储的结果,则它必须全部看到线程 1 中存储之前发生的所有操作,甚至是不相关的操作。

那么 x.store() 操作意味着所有对 memory 的读/写都应该更新相应的 memory 数据值是什么意思?

然后对于 std::memory_order_relaxed 意味着“没有线程可以指望来自另一个线程的特定排序”——这是什么意思——重新排序将由编译器完成,即使 y.store() 是,y 的值也不会被更新叫什么?

-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 */

For Acquire / release memory model 类似于顺序一致模式,只是它只对因变量应用 happens-before 关系。

Assuming 'x' and 'y' are initially 0:


 -Thread 1-
 y.store (20, memory_order_release);

 -Thread 2-
 x.store (10, memory_order_release);

 -Thread 3-
 assert (y.load (memory_order_acquire) == 20 && x.load (memory_order_acquire) == 0)

 -Thread 4-
 assert (y.load (memory_order_acquire) == 0 && x.load (memory_order_acquire) == 10)

用明确的术语来说是什么意思?

 -Thread 1-       -Thread 2-
 y = 1            if (x.load() == 2)
 x.store (2);        assert (y == 1)
  1. 自然地,编译器可能会更改不依赖于提高性能的操作顺序。
    但是当std::memory_order_seq_cst 起作用时,任何原子运算符都作为memory barrier工作。
    这并不意味着变量 y是原子变量,编译器只是保证y = 1; 发生在x.store (2); . 如果有另一个线程 3操作变量 y ,断言可能会由于另一个线程而失败。
    如果我的解释很难理解(由于我的英语不好......)请检查memory barrier & happened-before
    如果A发生在B关系建立之前,如果已经看到B的副作用,则所有线程都必须看到A的副作用。
-Thread 1-
y.store (20, memory_order_relaxed)  // 1-1
x.store (10, memory_order_relaxed)  // 1-2

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

-Thread 3-
if (y.load (memory_order_relaxed) == 10)  // 3-1
  assert (x.load(memory_order_relaxed) == 10) /* assert B */
  1. 要了解std::memory_order_relaxed ,您需要了解数据依赖性 显然, x & y彼此没有任何依赖关系。 因此编译器可能会更改线程 1的执行顺序,这与std::memory_order_seq_cst不同,其中y.store(20)必须x.store(10)发生之前执行。
    让我们看看每个断言是如何失败的。 我为每条指令添加了标签。

    断言 A : 1-2 → 2-1 →断言 A FAILED
    断言 B :请参阅帖子以获取详细答案。

    简而言之,线程 3可能会看到最终更新的变量 y并获得 10,但不是1-2的副作用。 即使线程 2必须看到它的副作用以便将 10 存储到 y 中,编译器也不保证指令的副作用必须在线程之间同步(发生之前
    另一方面,页面中的以下示例是指令具有数据依赖性时保留指令顺序的示例。 assert(y <= z)保证通过。
-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。 是否重新排序将由编译器完成,即使调用 y.store() 也可能不会更新 y 的值?
正如我在 2. 中所描述的,这意味着编译器可能会更改不具有数据依赖性的指令顺序。 当然,在y.store()时必须更新y 毕竟,这是原子指令的定义。

Assuming 'x' and 'y' are initially 0:


 -Thread 1-
 y.store (20, memory_order_release);

 -Thread 2-
 x.store (10, memory_order_release);

 -Thread 3-
 assert (y.load (memory_order_acquire) == 20 && x.load (memory_order_acquire) == 0)

 -Thread 4-
 assert (y.load (memory_order_acquire) == 0 && x.load (memory_order_acquire) == 10)
  1. 一致模式需要与所有数据发生先行关系。 所以在一致模式下, y.store()必须发生在x.store()之前,反之亦然。
    如果线程 3的断言通过,则意味着y.store()发生在x.store()之前。 所以线程 4必须在x.load() == 10之前看到y.load() == 20 因此断言失败。 如果线程 4的断言通过,也会发生同样的事情。
    acquire / release memory model 不强制与自变量发生先行关系。 因此可以在不违反任何规则的情况下进行以下命令。
    线程 4 y.load()线程 1 y.store()线程 3 y.load()线程 3 x.load()线程 4 x.load()
    结果两个断言都通过了。

暂无
暂无

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

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