[英]Why 'acquire/release' can not guarantee sequential consistency in c++11?
-Thread 1-
y.store (20, memory_order_release);
x.store (10, memory_order_release);
-Thread 2-
if (x.load(memory_order_acquire) == 10) {
assert (y.load(memory_order_acquire) == 20);
y.store (10, memory_order_release)
}
-Thread 3-
if (y.load(memory_order_acquire) == 10) {
assert (x.load(memory_order_acquire) == 10);
}
GCC Atomic Wiki paragraph “Overall Summary” says, the above code assert(x.load(memory_order_acquire))
can fail . GCC Atomic Wiki段落“Overall Summary”说,上面的代码
assert(x.load(memory_order_acquire))
可能会失败。 But I don't understand why ?但我不明白为什么?
My understanding is:我的理解是:
This is a bad example, though it does illustrate how mind-warping relaxed atomics can be, I suppose.这是一个糟糕的例子,尽管我想它确实说明了放松的原子是多么令人费解。
[intro.execution]p9: [介绍.执行]p9:
Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.
与完整表达式相关的每个值计算和副作用在与要评估的下一个完整表达式相关的每个值计算和副作用之前排序。
[atomics.order]p2: [atomics.order]p2:
An atomic operation A that performs a release operation on an atomic object M synchronizes with an atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A .
对原子对象M执行释放操作的原子操作A与对M执行获取操作的原子操作B同步,并从以A为首的释放序列中的任何副作用中获取其值。
As a result, the evaluations shown are chained together by sequenced-before and synchronized-with relationships:因此,显示的评估通过先序和同步关系链接在一起:
Thread 1 Thread 2 Thread 3
y.store(20)
|
| s.b.
V s.w.
x.store(10) --------> x.load() == 10
|
| s.b.
V s.w.
y.store(10) --------> y.load() == 10
|
| s.b.
V
x.load() == ?
And so each evaluation in the chain happens before the next (see [intro.races]p9-10).因此,链中的每个评估都发生在下一个之前(参见 [intro.races]p9-10)。
[intro.races]p15, [介绍.races]p15,
If a value computation A of an atomic object M happens before a value computation B of M , and A takes its value from a side effect X on M , then the value computed by B shall either be the value stored by X or the value stored by a side effect Y on M , where Y follows X in the modification order of M .
如果一个原子对象M的值计算A M的值计算B之前发生,并且A从M上的副作用X取它的值,然后用B中计算出的值应要么是或者存储在由X所存储的值的值由M上,副作用ÿ其中Y如下X在M的修改次序。
Here, A is the load in Thread 2 that took the value 10, B is the load in Thread 3 (in the assert).这里, A是线程 2 中取值为 10 的负载, B是线程 3 中的负载(在断言中)。 Since A happens before B , and there are no other side effects on
x
, B must also read 10.由于A发生在B之前,并且对
x
没有其他副作用,因此B也必须读取 10。
Herb Sutter has a much simpler example on his blog : Herb Sutter 在他的博客上有一个更简单的例子:
T1: x = 1;
T2: y = 1;
T3: if( x == 1 && y == 0 ) puts("x first");
T4: if( y == 1 && x == 0 ) puts("y first");
You absolutely need sequential consistency to guarantee that at most one line is printed.您绝对需要顺序一致性来保证最多打印一行。
Your example is special case of multithread program that only use atomic objects for synchronization, not for communicating information with significant entropy: the only values written act as milestones .您的示例是多线程程序的特例,它仅使用原子对象进行同步,而不是用于传递具有显着熵的信息:写入的唯一值充当里程碑。
It means that any store:这意味着任何商店:
The form must be exactly A.store (C, memory_order_release);
表单必须正好是
A.store (C, memory_order_release);
where:在哪里:
A
is an atomic object A
是原子对象C
is a constant C
是常数and the pair (A,C)
characterizes uniquely the program line.和对
(A,C)
唯一地表征程序行。
And conversely each load:相反,每个负载:
The form must be exactly表格必须完全正确
if (A.load(memory_order_acquire) == C) { ... }
where there is no else clause.没有 else 子句的地方。
Reading a particular value indicates progress and establish that all previous side effect (before a particular program point) have happened.读取特定值指示进度并确定所有先前的副作用(在特定程序点之前)已经发生。 That small class of programs never has funny multithread behavior because everything is a function of progress: milestones are passed, and the behavior must be purely sequential.
这一小类程序从来没有有趣的多线程行为,因为一切都是进程的函数:里程碑被传递,行为必须是纯顺序的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.