load-acquire 应该立即看到 store-release 吗?
Should load-acquire see store-release immediately?
假设我们有一个简单的变量(std::atomic<int> var
)和 2 个线程 T1
和 T2
并且我们有以下用于 T1
的代码:
...
var.store(2, mem_order);
...
和 T2
...
var.load(mem_order)
...
我们还假设 T2
(load) 比 T1
执行 123ns (根据 C++ 标准的修改顺序) ](店铺)。
我对这种情况的理解如下(针对不同的内存顺序):
memory_order_seq_cst
- T2
load 有义务加载2
。如此有效,它必须加载最新值(就像 RMW 操作的情况一样)
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
在存储操作之前进入线程 T1
,OP2
在它之后,OP3
在加载操作之前进入线程 T2
, OP4
紧随其后。
//T1: //T2:
OP1 OP3
var.store(2, mem_order) var.load(mem_order)
OP2 OP4
假设线程可以观察到 var.store()
和 var.load()
之间的某种顺序。 其他操作的跨线程顺序有什么可以保证的?
- 如果
var.store
使用memory_order_release
,var.load
使用memory_order_acquire
并且var.store
在之前var.load
(即加载returns2),则OP1
的效果顺序为beforeOP4
.
例如,如果 OP1
写入某个变量 var1,OP4
读取该变量,那么可以确信 OP4
将读取 OP1
之前写入的内容。这是使用最多的案例。
- 如果
var.store
和 var.load
都使用 memory_order_seq_cst
并且 var.store
被排序 在 var.load
之后(即是,加载 returns 0,这是存储前变量的值),然后 OP2
的效果被排序 after OP3
.
一些棘手的同步方案需要此内存顺序。
- 如果
var.store
或var.load
使用memory_order_relaxed
,那么var.store
和var.load
的任何顺序都可以保证没有跨线程操作的顺序。
此内存顺序用于万一 其他人 确保操作顺序。例如,如果线程 T2
在 T1
中的 var.store
之后创建,则 OP3
和 OP4
排在 OP1
之后。
UPDATE: 123 ns later
意味着 *someone else* force ordering
因为计算机的处理器没有关于世界时的概念,并且没有操作有 精确时刻 执行时。对于两次操作之间的测量时间,您应该:
- 观察 一些 cpu.
上完成第一个操作和开始计时操作之间的顺序
- 注意开始和结束计时操作之间的顺序。
- 注意完成计时操作和开始第二个操作之间的顺序。
传递性地,这些步骤在第一个操作和第二个操作之间进行排序。
没有找到任何论据证明我的理解是错误的我认为是正确的,我的证明如下:
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 的物理内存与两个线程处理器相距一定距离,则效果类似。
假设我们有一个简单的变量(std::atomic<int> var
)和 2 个线程 T1
和 T2
并且我们有以下用于 T1
的代码:
...
var.store(2, mem_order);
...
和 T2
...
var.load(mem_order)
...
我们还假设 T2
(load) 比 T1
执行 123ns (根据 C++ 标准的修改顺序) ](店铺)。
我对这种情况的理解如下(针对不同的内存顺序):
memory_order_seq_cst
-T2
load 有义务加载2
。如此有效,它必须加载最新值(就像 RMW 操作的情况一样)memory_order_acquire
/memory_order_release
/memory_order_relaxed
-T2
没有义务加载2
但可以加载任何旧值,唯一的限制是:值不应早于该线程加载的最新值。因此,例如var.load
returns0
.
我的理解对吗?
更新1:
如果我的推理有误,请提供证明它的 C++ 标准文本。不仅仅是一些架构可能如何工作的理论推理。
Am I right with my understanding?
没有。你误解了内存顺序。
let's assume that
T2
(load) executes 123ns later thanT1
(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
在存储操作之前进入线程 T1
,OP2
在它之后,OP3
在加载操作之前进入线程 T2
, OP4
紧随其后。
//T1: //T2:
OP1 OP3
var.store(2, mem_order) var.load(mem_order)
OP2 OP4
假设线程可以观察到 var.store()
和 var.load()
之间的某种顺序。 其他操作的跨线程顺序有什么可以保证的?
- 如果
var.store
使用memory_order_release
,var.load
使用memory_order_acquire
并且var.store
在之前var.load
(即加载returns2),则OP1
的效果顺序为beforeOP4
.
例如,如果 OP1
写入某个变量 var1,OP4
读取该变量,那么可以确信 OP4
将读取 OP1
之前写入的内容。这是使用最多的案例。
- 如果
var.store
和var.load
都使用memory_order_seq_cst
并且var.store
被排序 在var.load
之后(即是,加载 returns 0,这是存储前变量的值),然后OP2
的效果被排序 afterOP3
.
一些棘手的同步方案需要此内存顺序。
- 如果
var.store
或var.load
使用memory_order_relaxed
,那么var.store
和var.load
的任何顺序都可以保证没有跨线程操作的顺序。
此内存顺序用于万一 其他人 确保操作顺序。例如,如果线程 T2
在 T1
中的 var.store
之后创建,则 OP3
和 OP4
排在 OP1
之后。
UPDATE: 123 ns later
意味着 *someone else* force ordering
因为计算机的处理器没有关于世界时的概念,并且没有操作有 精确时刻 执行时。对于两次操作之间的测量时间,您应该:
- 观察 一些 cpu. 上完成第一个操作和开始计时操作之间的顺序
- 注意开始和结束计时操作之间的顺序。
- 注意完成计时操作和开始第二个操作之间的顺序。
传递性地,这些步骤在第一个操作和第二个操作之间进行排序。
没有找到任何论据证明我的理解是错误的我认为是正确的,我的证明如下:
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 的物理内存与两个线程处理器相距一定距离,则效果类似。