std::atomic memory_order 含义
主要参考并翻译自 Memory model synchronization modes
Sequentially Consistent
严格的顺序执行,不知道如何描述,看例子
-Thread 1- -Thread 2-
y = 1 if (x.load() == 2)
x.store (2); assert (y == 1)
上例中如果 T2 if
触发,即它看到了 T1 的 x.store(2)
动作,那么可以保证 T1 已经完成了 y 的赋值
a = 0
y = 0
b = 1
-Thread 1- -Thread 2-
x = a.load() while (y.load() != b)
y.store (b) ;
while (a.load() == x) a.store(1)
;
上例中,如果 T2 的 loop 结束,即它看到了 T1 对 y 的 store,则 T1 一定完成了 x = a.load()
,而当 T2 完成 a 的 store 后,T1 的 loop 才会结束
-Thread 1- -Thread 2- -Thread 3-
y.store (20); if (x.load() == 10) { if (y.load() == 10)
x.store (10); assert (y.load() == 20) assert (x.load() == 10)
y.store (10)
}
上例的几个 assertion 均成立
Relaxed
memory_order_seq_cst 模型提供的是 happens-before 约束,relaxed 则去除了这一约束
例子
-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 */
这是刚才的例子,但在 relaxed 模型下两个 assertion 均可能 FAIL。例如当 T2 观测到 x == 10 时,T1 可能并未将 20 写到 y
但即使在 relaxed 的模型下,对同一变量的多次修改仍然是顺序的,例如
x = 0
-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)
这个例子中的 assertion 永远不会 FAIL,如果在 T2 中 x load 到了 2,那么一定不会再 load 到 1
Acquire/Release
是前面两个模型的混合,Acquire/Release 只对互相依赖的变量保证 happens-before,没太看懂原文的例子,参考 Understanding memory_order_acquire
and memory_order_release
in C++11
memory_order_release 可以提交本线程在此之前的所有变更,而 acquire 到的线程一定能见到被 release 的变更。这里的变更包括非 atomic 变量,即当作 memory barrier 用
Consume
比 Acquire/Release 更松的模型,Acquire/Release 下所有 load 之后的读写都不许被移动到 load 之前,即在 load 时强制同步,但 Consume 模式下只有依赖原子变量的读写才会保证在 load 之后
n = 0
m = 0
-Thread 1-
n = 1
m = 1
p.store (&n, memory_order_release)
-Thread 2-
t = p.load (memory_order_acquire);
assert( *t == 1 && m == 1 );
-Thread 3-
t = p.load (memory_order_consume);
assert( *t == 1 && m == 1 );
T2 中的 assertion 一定 PASS,因为 Acquire load 一定会同步 n = 1; m = 1
T3 中的 assertion 可能 FAIL,因为 Consume load 只会同步 n = 1
,不保证同步 m