[英]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段落“Overall Summary”說,上面的代碼assert(x.load(memory_order_acquire))
可能會失敗。 但我不明白為什么?
我的理解是:
這是一個糟糕的例子,盡管我想它確實說明了放松的原子是多么令人費解。
[介紹.執行]p9:
與完整表達式相關的每個值計算和副作用在與要評估的下一個完整表達式相關的每個值計算和副作用之前排序。
[atomics.order]p2:
對原子對象M執行釋放操作的原子操作A與對M執行獲取操作的原子操作B同步,並從以A為首的釋放序列中的任何副作用中獲取其值。
因此,顯示的評估通過先序和同步關系鏈接在一起:
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() == ?
因此,鏈中的每個評估都發生在下一個之前(參見 [intro.races]p9-10)。
[介紹.races]p15,
如果一個原子對象M的值計算A M的值計算B之前發生,並且A從M上的副作用X取它的值,然后用B中計算出的值應要么是或者存儲在由X所存儲的值的值由M上,副作用ÿ其中Y如下X在M的修改次序。
這里, A是線程 2 中取值為 10 的負載, B是線程 3 中的負載(在斷言中)。 由於A發生在B之前,並且對x
沒有其他副作用,因此B也必須讀取 10。
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");
您絕對需要順序一致性來保證最多打印一行。
您的示例是多線程程序的特例,它僅使用原子對象進行同步,而不是用於傳遞具有顯着熵的信息:寫入的唯一值充當里程碑。
這意味着任何商店:
表單必須正好是A.store (C, memory_order_release);
在哪里:
A
是原子對象C
是常數和對(A,C)
唯一地表征程序行。
相反,每個負載:
表格必須完全正確
if (A.load(memory_order_acquire) == C) { ... }
沒有 else 子句的地方。
讀取特定值指示進度並確定所有先前的副作用(在特定程序點之前)已經發生。 這一小類程序從來沒有有趣的多線程行為,因為一切都是進程的函數:里程碑被傳遞,行為必須是純順序的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.