簡體   English   中英

C++ std::memory_order_relaxed 混亂

[英]C++ std::memory_order_relaxed confusion

我正在閱讀 GCC Wiki 上關於 C++ 內存障礙(及其很棒)的這篇文章
在我到達這一點之前,它非常簡單:

相反的方法是 std::memory_order_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 */

由於線程不需要跨系統同步,因此本示例中的任一斷言實際上都可能失敗。

好的,這也很簡單,讓我們繼續..

-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)

斷言不能失敗。 一旦線程 2 看到 2 的存儲,它就不能再看到值 1。這可以防止將一個變量的松弛加載與可能別名的不同引用的松弛加載合並。

這讓我很困惑,為什么 y 不能加載值 2 而 z 加載值 1(並導致斷言失敗),因為排序在線程 1 中不同步?

松弛排序是相對於其他內存訪問的操作順序而言的,而不是相對於被松弛修改的原子的排序。 在您的第一種情況下,您可以在x中看到 10 這一事實對於y的值沒有任何意義。 反之亦然。

但是你的第二種情況不同,因為它影響同一個原子對象。

[intro.races]/10告訴我們,在一個線程中,如果一個操作在另一個之前被排序,那么該操作“發生在”另一個之前。 [intro.races]/14-17 概述了關於原子的以下行為

前面的四個一致性要求有效地禁止編譯器將原子操作重新排序為單個對象,即使這兩個操作都是寬松加載。

這就是你在這里所擁有的。 所有的修改都發生在同一個對象上,所以它們必須以某種順序發生。 即使無法准確確定該順序,該順序也必須尊重代碼的“先發生”關系。

線程 1 的兩個操作按“先發生”關系排序。 並且線程 2 的操作本身是由“發生在之前”關系排序的。

由於它們都作用於同一個原子對象,如果y的值是 2,那么它一定是“發生在” x被設置為 2 之后。所以x的訪問順序一定是“x = 1, x = 2,讀取 x"。 由於最后一次讀取x發生在第一次讀取x ,所以它得到的值不能為 1。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM