是否应该立即加载获取商店发布?

ixS*_*Sci 6 c++ multithreading atomic atomicity

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

...
var.store(2, mem_order);
...
Run Code Online (Sandbox Code Playgroud)

并为 T2

...
var.load(mem_order)
...
Run Code Online (Sandbox Code Playgroud)

另外,我们假设T2(load)执行时间晚于123ns (在C++标准的修改顺序中稍后),而不是T1(store).我对这种情况的理解如下(针对不同的内存顺序):

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

我的理解是对的吗?

UPDATE1:

如果我的推理错了,请提供C++标准中的文本证明.不仅仅是一些架构如何运作的理论推理.

Tsy*_*rev 5

我的理解对吗?

不,你误解了内存顺序。

让我们假设T2(load) 执行比T1(store)晚 123ns ...

在这种情况下,T2 将看到 T1 对任何类型的内存订单做了什么(此外,此属性适用于任何内存区域的读/写,参见例如http://www.open-std.org/jtc1/sc22/ wg21/docs/papers/2015/n4431.pdf , 1.10, p.15)。你的短语中的关键词是after:这意味着其他人强制对这些操作进行排序。

内存命令用于其他场景:

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

//T1:                         //T2:
OP1                           OP3
var.store(2, mem_order)       var.load(mem_order)
OP2                           OP4
Run Code Online (Sandbox Code Playgroud)

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

  1. 如果var.store使用memory_order_releasevar.load使用memory_order_acquire在之前var.store排序(即加载返回2),则效果在之前排序。 var.loadOP1 OP4

例如,如果OP1写入某个变量 var1,OP4读取该变量,则可以确保OP4读取OP1之前写入的内容。这是最常用的情况。

  1. 如果var.storeand 都var.load使用memory_order_seq_cstand在之后var.store排序(即 load 返回 0,这是存储之前变量的值),则 effect of在 之后排序。 var.loadOP2 OP3

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

  1. 如果任一var.storevar.load用途memory_order_relaxed,然后用任何顺序var.storevar.load一个可以garantee没有秩序横纱的操作。

其他人确保操作顺序时,将使用此内存顺序。例如,如果线程T2创建在var.storein之后T1,则OP3OP4在 之后排序OP1

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

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

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


ixS*_*Sci 1

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

\n\n
\n

memory_order_seq_cst - T2 加载必须加载 2。

\n
\n\n

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

\n\n
\n

[29.9/3]所有 memory_order_seq_cst\n 操作上应有一个总顺序 S,与所有受影响位置的 \xe2\x80\x9d 顺序和\n 修改顺序之前发生的 \xe2\x80\x9 一致,使得每个\n memory_order_seq_cst 从原子对象 M 加载值的操作 B 观察到以下值之一 <...>

\n
\n\n

我的下一个问题是:

\n\n
\n

memory_order_acquire/memory_order_release/memory_order_relaxed - T2 没有义务加载 2,但可以加载任何较旧的值 <...>

\n
\n\n

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

\n\n
\n

[29.3/12]实现应该使原子存储在合理的时间内对原子加载可见。

\n
\n\n

\n\n
\n

[1.10/28]实现应确保原子或同步操作分配的最后一个值(按修改顺序)\n 将在有限的时间内对所有其他线程可见。

\n
\n\n

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

\n\n

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

\n