load-acquire 应该立即看到 store-release 吗?

Should load-acquire see store-release immediately?

假设我们有一个简单的变量(std::atomic<int> var)和 2 个线程 T1T2 并且我们有以下用于 T1 的代码:

...
var.store(2, mem_order);
...

T2

...
var.load(mem_order)
...

我们还假设 T2(load) 比 T1 执行 123ns (根据 C++ 标准的修改顺序) ](店铺)。 我对这种情况的理解如下(针对不同的内存顺序):

  1. memory_order_seq_cst - T2 load 有义务加载2。如此有效,它必须加载最新值(就像 RMW 操作的情况一样)
  2. memory_order_acquire/memory_order_release/memory_order_relaxed - T2 没有义务加载 2 但可以加载任何旧值,唯一的限制是:值不应早于该线程加载的最新值。因此,例如 var.load returns 0.

我的理解对吗?

更新1:

如果我的推理有误,请提供证明它的 C++ 标准文本。不仅仅是一些架构可能如何工作的理论推理。

Am I right with my understanding?

没有。你误解了内存顺序。

let's assume that T2(load) executes 123ns later than T1(store)...

在那种情况下,T2 将看到 T1 对任何类型的内存顺序做了什么(此外,这个 属性 应用于任何内存区域的 read/write,例如 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4431.pdf , 1.10, 第 15 页)。您的短语中的关键字是 later:这意味着 someone else 强制对这些操作进行排序。

内存顺序用于其他场景:

让一些操作 OP1 在存储操作之前进入线程 T1OP2 在它之后,OP3 在加载操作之前进入线程 T2 , OP4 紧随其后。

//T1:                         //T2:
OP1                           OP3
var.store(2, mem_order)       var.load(mem_order)
OP2                           OP4

假设线程可以观察到 var.store()var.load() 之间的某种顺序。 其他操作的跨线程顺序有什么可以保证的?

  1. 如果var.store使用memory_order_releasevar.load使用memory_order_acquire并且var.store之前var.load(即加载returns2),则OP1的效果顺序为beforeOP4.

例如,如果 OP1 写入某个变量 var1,OP4 读取该变量,那么可以确信 OP4 将读取 OP1 之前写入的内容。这是使用最多的案例。

  1. 如果 var.storevar.load 都使用 memory_order_seq_cst 并且 var.store 被排序 var.load 之后(即是,加载 returns 0,这是存储前变量的值),然后 OP2 的效果被排序 after OP3.

一些棘手的同步方案需要此内存顺序。

  1. 如果var.storevar.load使用memory_order_relaxed,那么var.storevar.load的任何顺序都可以保证没有跨线程操作的顺序

此内存顺序用于万一 其他人 确保操作顺序。例如,如果线程 T2T1 中的 var.store 之后创建,则 OP3OP4 排在 OP1 之后。

UPDATE: 123 ns later 意味着 *someone else* force ordering 因为计算机的处理器没有关于世界时的概念,并且没有操作有 精确时刻 执行时。对于两次操作之间的测量时间,您应该:

  1. 观察 一些 cpu.
  2. 上完成第一个操作和开始计时操作之间的顺序
  3. 注意开始和结束计时操作之间的顺序。
  4. 注意完成计时操作和开始第二个操作之间的顺序。

传递性地,这些步骤在第一个操作和第二个操作之间进行排序。

没有找到任何论据证明我的理解是错误的我认为是正确的,我的证明如下:

memory_order_seq_cst - T2 load is obliged to load 2.

这是正确的,因为所有使用 memory_order_seq_cst 的操作都应该在所有内存操作的原子变量上形成单一的总顺序。 标准摘录:

[29.9/3] There shall be a single total order S on all memory_order_seq_cst operations, consistent with the “happens before” order and modification orders for all affected locations, such that each memory_order_seq_cst operation B that loads a value from an atomic object M observes one of the following values <...>

我的问题的下一点:

memory_order_acquire/memory_order_release/memory_order_relaxed - T2 is not obliged to load 2 but can load any older value <...>

我没有找到任何证据表明在修改顺序中稍后执行的加载应该看到最新的值。对于内存顺序不同于 memory_order_seq_cst 的 store/load 操作,我发现的唯一要点是:

[29.3/12] Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.

[1.10/28] An implementation should ensure that the last value (in modification order) assigned by an atomic or synchronization operation will become visible to all other threads in a finite period of time.

所以我们唯一的保证是写入的变量将在一段时间内可见 - 这是相当合理的保证,但并不意味着先前存储的立即可见性。这证明了我的第二点。

鉴于我最初的理解是正确的。

123 nS 之后不会强制执行看到 T1 结果的 T2。那是因为如果物理程序计数器(晶体管等)运行T2距离物理程序计数器运行T1(大型多核超级计算机等)超过40米,那么速度光将不允许 T1 写入状态信息传播那么远(还)。如果用于 load/stores 的物理内存与两个线程处理器相距一定距离,则效果类似。