[英]Race condition on x86
有人可以解釋一下這個說法:
shared variables
x = 0, y = 0
Core 1 Core 2
x = 1; y = 1;
r1 = y; r2 = x;
x86 處理器上怎么可能有r1 == 0
和r2 == 0
?
該問題可能是由於涉及指令重新排序的優化而出現的。 換句話說,兩個處理器都可以在分配變量x
和y
之前分配r1
和r2
,如果他們發現這會產生更好的性能。 這可以通過添加memory 屏障來解決,這將強制執行排序約束。
引用您在帖子中提到的幻燈片:
現代多核/語言打破了順序一致性。
關於 x86 架構,最好的閱讀資源是英特爾® 64 和 IA-32 架構軟件開發人員手冊(第8.2 章 Memory 訂購)。 8.2.1 和 8.2.2 節描述了由 Intel486、Pentium、Intel Core 2 Duo、Intel Atom、Intel Core Duo、Pentium 4、Intel Xeon 和 P6 系列處理器實現的內存排序:memory Z20F35E630DAF44DBFA4C3F68F5399DC8處理器稱為 ordering ,與舊 Intel386 架構的程序排序(強排序)相反(其中讀取和寫入指令始終按照它們在指令流中出現的順序發出)。
該手冊描述了處理器訂購 memory model 的許多訂購保證(例如, Loads 不會與其他負載一起重新排序,Stores 不會與其他存儲一起重新排序, Stores 不會與舊負載一起重新排序等),但它也描述了允許的重新排序規則這導致了 OP 帖子中的競爭條件:
8.2.3.4 加載可能會與早期存儲重新排序到不同的位置
另一方面,如果指令的原始順序被切換:
shared variables
x = 0, y = 0
Core 1 Core 2
r1 = y; r2 = x;
x = 1; y = 1;
在這種情況下,處理器保證r1 = 1
和r2 = 1
的情況是不允許的(由於8.2.3.3 Stores Are Not Reordered With Early Load保證),這意味着這些指令永遠不會在單個內核中重新排序。
要將其與不同的架構進行比較,請查看這篇文章: Memory 在現代微處理器中的排序。 您可以看到 Itanium (IA-64) 比 IA-32 架構進行了更多的重新排序:
On processors with a weaker memory consistency model (such as SPARC, PowerPC, Itanium, ARM, etc.), the above condition can take place because of a lack of enforced cache-coherency on writes without an explicit memory barrier instruction. 所以基本上Core1
在y
之前看到x
上的寫入,而Core2
在x
之前看到在y
上的寫入。 在這種情況下,不需要完整的柵欄指令......基本上,您只需要在這種情況下強制執行寫入或釋放語義,以便在對那些已經被寫給。 具有強大 memory 一致性模型(如 x86)的處理器架構通常不需要這樣做,但正如 Groo 指出的那樣,編譯器本身可以重新排序操作。 您可以在 C 和 C++ 中使用volatile
關鍵字來防止編譯器在給定線程中對操作進行重新排序。 這並不是說volatile
會創建線程安全的代碼來管理線程之間讀寫的可見性......需要一個 memory 屏障。 因此,雖然使用volatile
仍會創建不安全的線程代碼,但在給定線程內,它將在已編譯的機器代碼級別強制執行順序一致性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.