假设我们有一个简单的变量(std::atomic<int> var
)和2个线程T1
和T2
,我们有T1
的以下代码:
...
var.store(2, mem_order);
...
和T2
...
var.load(mem_order)
...
另外,我们假设T2
(加载)稍后执行123ns (稍后在C ++标准的修改顺序中),而不是T1
(存储)。
我对这种情况的理解如下(针对不同的记忆顺序):
memory_order_seq_cst
- T2
加载必须加载2
。因此,它必须有效地加载最新值(就像RMW操作的情况一样)memory_order_acquire
/ memory_order_release
/ memory_order_relaxed
- T2
没有义务加载2
,但可以使用唯一限制加载任何旧值:该值应该不比该线程加载的最新版本旧。因此,例如var.load
会返回0
。我的理解是对的吗?
UPDATE1:
如果我的推理错了,请提供C ++标准中的文本证明。不仅仅是对某些架构如何运作的理论推理。
答案 0 :(得分:4)
我的理解是对的吗?
没有。你误解了记忆顺序。
让我们假设
T2
(加载)比T1
(商店)执行晚了123 ... ...
在这种情况下,T2将看到T1对任何类型的内存顺序所做的事情(此外,此属性适用于任何内存区域的读/写,参见例如http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4431.pdf,1.10,第15页)。您的短语中的关键词是以后:这意味着其他人会强制对这些操作进行排序。
内存订单用于其他场景:
让一些操作OP1
在存储操作之前出现在线程T1
中,OP2
出现在它之后,OP3
在加载操作之前进入线程T2
,{ {1}}来到它之后。
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
之前订购(是,加载返回2),然后var.load
的效果在 OP1
之前排序。,如果OP4
写了一些变量var1,OP1
读取该变量,那么可以确保OP4
将读取之前写的OP4
。这是最常用的案例。
OP1
和var.store
同时使用var.load
而memory_order_seq_cst
在 var.store
后排序(即加载返回0) ,这是存储前变量的值),然后var.load
的效果在 OP2
后排序。某些棘手的同步方案需要此内存顺序。
OP3
或var.store
使用var.load
,那么对于memory_order_relaxed
和var.store
的任何订单,都可以保证无订单跨线程操作。当其他人确保操作顺序时,使用此内存顺序。例如,如果在var.load
T2
之后创建线程var.store
,则在T1
之后订购OP3
和OP4
。
更新:OP1
隐含123 ns later
,因为计算机的处理器没有关于通用时间的概念,并且没有操作精确时刻什么时候执行。对于两次操作之间的测量时间,您应该:
传递上,这些步骤在第一个操作和第二个操作之间进行排序。
答案 1 :(得分:1)
没有发现任何证据证明我的理解错误,我认为这是正确的,我的证据如下:
memory_order_seq_cst - T2负载必须加载2.
这是正确的,因为使用memory_order_seq_cst
的所有操作应该在所有内存操作的原子变量上形成单个总顺序。
摘自标准:
[29.9 / 3] 所有memory_order_seq_cst上应该有一个总订单S 操作,符合“之前发生”的顺序和 所有受影响位置的修改订单,例如每个 memory_order_seq_cst操作B从原子加载值 对象M观察以下值之一&lt; ...&gt;
我的问题的下一点:
memory_order_acquire / memory_order_release / memory_order_relaxed - T2是 没有义务加载2但可以加载任何旧值&lt; ...&gt;
我没有找到任何可能表明稍后在修改订单中执行的加载应该看到最新值的证据。我发现存储/加载操作的唯一要点是任何与memory_order_seq_cst
不同的内存顺序是:
[29.3 / 12] 实现应该使原子存储对原子可见 在合理的时间内装载。
和
[1.10 / 28] 实现应确保原子或同步操作分配的最后一个值(按修改顺序) 将在有限的时间内对所有其他线程可见。
因此,我们唯一的保证是写入的变量将在一段时间内可见 - 这是非常合理的保证,但并不意味着前一个商店的即时可见性。这证明了我的第二点。
鉴于我最初的理解是正确的。
答案 2 :(得分:0)
123 ns 之后不会强制对 T2 进行排序以查看 T1 的结果。那是因为如果运行 T2 的物理程序计数器(晶体管等)与运行 T1 的物理程序计数器(大型多核超级计算机等)相距 40 米以上,那么光速将不允许 T1 写入状态信息传播那么远(还)。如果用于加载/存储的物理内存与两个线程处理器相距一定距离,则效果类似。