假設我們有一個多線程的C程序(pthreads),並且各個線程的(非同步)共享變量訪問不會被編譯器重新排序。 x86 CPU是否尊重共享變量訪問的順序(在單個線程中),還是有可能重新排序某些內存訪問?多線程和無序執行
多線程和無序執行
回答
非同步共享變量訪問是危險的,並且亂序是其原因之一。
x86保持寫入順序(在一個線程內),但不能讀取。
如果您認爲訂單仍然存在,這可能會讓您陷入困境。例如:
線程A寫入x然後寫入y。假設編譯器沒有對它重新排序,CPU不會重新排序(x86不會,其他可能)。
線程B讀取y,然後讀取x。你可能會認爲,如果它具有y的新價值,那麼你肯定也會得到x的新價值。
並非如此。 CPU可能會對線程B的讀取進行重新排序,所以y會被更早讀取。
編輯:爲「單向的男人」中指出,在這種情況下,X86保證排序(但不是所有的處理器!)。
我引用英特爾軟件開發人員手冊:
寫入由單個處理器中所有 處理器相同的順序觀察。
這對於多處理器寫入來說並不正確 - 它們看起來可能被不同的處理器按不同的順序排列。
但是,我強烈建議不要依賴它,並使用適當的同步來代替。
同步原語是通過原子操作和/或障礙來實現的,它們保證您的安全。
您是否可以用另一次讀取重新排序讀取? 「線程B讀取y然後讀取x,您可能會認爲如果它獲得了y的新值,那麼您肯定也會得到x的新值。」我不認爲這是真實的根據英特爾手冊:「讀取不會與其他讀取重新排序」。閱讀可以重新排序與舊的寫作雖然。 – 2013-09-09 20:33:32
@ManofOneWay,你說得對。該手冊還指出「所有處理器以相同順序觀察單個處理器寫入」。我認爲,我的底線是正確的 - 根據這些細節編寫正確的無同步代碼幾乎是不可能的。 – ugoren 2013-09-10 08:51:58
x86在加載和舊存儲時不保證排序,因此如果存在A然後是加載B,並且它們引用不同的存儲位置,則加載B可能會在A之前移動。因此,隔離仍然存在在某些情況下需要。 – 2013-09-10 09:02:07
由於存儲緩衝區的存在,一些重新排序是可能的。見例如https://www.cl.cam.ac.uk/~pes20/weakmemory/cacm.pdf
但是,重排序只能看到幾個線程,在單個線程中,該線程的所有訪問都按順序發生。
- 1. 執行多線程程序
- 2. 多次執行線程和運行程序的區別
- 3. 並行執行和終止多線程
- 4. 瞭解多線程和執行過程
- 5. 執行多線程進程
- 6. 多線程代碼 - 力執行順序
- 7. 多線程與亂序執行的
- 8. 多線程和委託執行
- 9. 線程池執行程序
- 10. 暫停/執行多線程程序中的一個線程(C#)
- 11. 強制Eclipse執行多線程Java程序單線程
- 12. 多線程程序只執行最後創建的線程?
- 13. 如何執行多線程應用程序作爲線程?
- 14. 多線程執行寫入?
- 15. 多線程執行模式
- 16. 多線程TestNG DataProvider執行
- 17. 執行多個線程
- 18. 多線程同步執行
- 19. 在多線程程序中執行另一個程序
- 20. 正確使用JavaFX任務執行多線程和線程池
- 21. CUDA線程執行順序
- 22. 線程執行時序
- 23. 已排序執行線程
- 24. boost ::線程執行順序
- 25. 執行線程的順序
- 26. 線程執行序列
- 27. 線程執行順序
- 28. 執行程序優於多線程應用程序中的線程
- 29. Java:另一個多線程執行程序中的單線程子執行程序
- 30. 爲什麼我的多線程程序按順序執行?
無序/推測調度執行只存在於微代碼級別(後端)。 (請通知@我,因爲我沒有手動檢查答案) – user2284570 2013-11-23 01:47:22