簡體   English   中英

重新排序C ++中的原子操作

[英]reordering atomic operations in C++

假設我有2個線程:

int value = 0;
std::atomic<bool> ready = false;

thread 1:
value = 1
ready = true;

thread 2:
while (!ready);
std::cout << value;

這個程序能輸出0嗎?

我讀到了有關C ++內存模型的信息-具體來說,是順序一致性,我認為這是默認設置,但並不是特別清楚。 是僅要求編譯器相對於彼此以正確的順序放置原子操作,還是相對於所有其他操作以正確的順序放置原子操作?

默認情況下,對原子變量的操作是使用memory_order_seq_cst語義完成的,這保證了不會進行任何重新排序。

因此,行: value = 1不能在原子分配: value = 1以下重新排序,因此行std::cout << value; 將始終打印1。

按照相同的規則,行: std::cout << value; 不能重新排序
在行上方: while (!ready);

根據ShadowRanger的響應,它就像一個內存屏障。 但是,有關其原因的更多詳細信息,我建議查看Herb Sutter關於原子武器的演講 他詳細介紹了原子如何工作以及為什么工作。

這個程序能輸出0嗎?

不行

您的推論是正確的。 在ISO C ++中,seq_cst和acq_rel原子可以在線程之間的關系之前/之后創建事件,從而使一個線程可以安全地寫入非原子變量,然后另一個線程可以在沒有數據爭用UB的情況下讀取它。

在這種情況下,您已經正確地做到了:spin-wait循環是來自該標志的seq-cst加載,僅當看到一個true值時才退出該循環。 非原子value的評估發生在看到true載荷之后。 並且在編寫器中,順序發布存儲區確保在值存儲區之前看不到標志存儲區。


當為常規ISA編譯為asm時,編譯器必須遵循發布發布之前非原子存儲的順序,以及獲取負載之后的非原子負載的順序。 除非它能以某種方式證明觀察到此情況的任何其他可能的線程仍然存在UB。

是的,但這僅是因為您使用了默認設置。

Cst受苦是因為它使用全局范圍進行重新排序。 這是舊架構的產物。 較新的體系結構具有更大的排序范圍,因此您可能希望標准更新會在不久的將來使您的代碼無效。

寫隊列最終可能包含數十個條目,每個條目的解析度對總線的等待時間都非常大。 將這些問題划分為重要問題與不重要問題是顯而易見的一步,這是新體系結構已經體現的一步。

C ++ 標准創建委員會顯然已經超出其深度,應該停止發明無用的廢話。

首先請注意:由於存在UB(未定義行為)的可能性,因為沒有明確定義的抽象線程語義,或者存在任何語義,因此絕對不可能推理任何支持線程的C和C ++版本中的任何C或C ++程序。全部定義。 這是C和C ++語義的又一個主要理論以及實際缺陷(在許多其他嚴重缺陷之外)。

但是您可以用實際的理由進行推理:編譯器在執行線程原語方面非常可預測(將來可能不會如此,因為編譯器編寫者精通線程語義並開始使用UB聲明破壞事物)。

使用線程通信原語時,編譯器會做正確的事情以保證信息流。 while (!ready); 確保設置原子對象之后線程退出循環:存在定義明確的“過去”。

作為現實世界中定義不正確的“過去”的示例,請記住與宇航員在休斯敦交談時進行的阿波羅音頻交換:由於宇航員距離很遠,因此沒有明確的概念是誰首先開始交談,這是我們僅有的錄音(來自休斯頓)顯示了一個命令,但是從飛船上獲得的假設記錄將顯示另一個命令,而這兩個命令都不正確。 宇航員和休斯頓開始無秩序地談話,這兩個都不是過去。 在看到這一點之前,您不能聲稱理解相對論。

有了多線程, 您可以擁有不屬於其他人的內存操作 ,並且不知道如果他們嘗試使用非過去操作的對象,他們將觀察到什么。

暫無
暫無

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

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