筆者知識和理解水平有限,歡迎指出不足之處html
推薦閱讀
在上篇文章 深刻講解併發編程模型之概念 比較詳細分析了併發編程模型的相關概念。這篇文章就深刻講解下關於重排序的問題。編程
重排序分爲:segmentfault
其中,只要對單線程的語義(實際上能夠理解爲單線程執行結果)不產生影響,<span style="color:blue">編譯器</span>在編譯源代碼的時候就能夠從新編排程序語句的執行順序。這就是編譯器優化的重排序。緩存
若是對程序執行結果不產生影響,處理器能夠優化程序指令的運行順序,通常是採用並行的方式來執行指令。那麼,如何判斷改變指令的執行方式不會影響程序運行結果呢?其實能夠根據指令之間是否有數據依賴。,<span style="color:blue">具備數據依賴的指令不能更改執行順序,沒有的能夠修改,不會影響程序執行結果。</span>這就是指令級並行的重排序。什麼是數據依賴性,下面會講。安全
接下來,什麼是內存系統重排序呢?咱們先來了解如下有關處理器緩存的知識。多線程
咱們知道,處理器爲了加速對數據的讀取,採用了三級緩存的策略。下面,先來分析CPU三級緩存是什麼回事。併發
CPU與內存之間的臨時數據交換器,它的出現是爲了解決CPU運行處理速度與內存讀寫速度不匹配的矛盾——緩存的速度比內存的速度快多了。優化
首先,咱們來看看CPU三級緩存在計算機存儲系統中處於哪一個位置:spa
計算機存儲系統:線程
CPU三級緩存:
名詞解釋
執行速度:L1 > L2 > L3
咱們能夠看到,CPU緩存是直接和主存進行數據交換的。由於CPU緩存執行速度遠遠大於主存,咱們能夠把經常使用的數據緩存在CPU緩存中,大大提升指令的的執行速度。CPU緩存具體的工做原理不在這裏講,有興趣的同窗能夠翻看相關書籍。
回到咱們講的重排序。這裏咱們就能夠分析如下內存系統重排序了。
在上面CPU三級緩存系統中,實現緩存一致性機制有兩種。
若是CPU讀取一個數據,就會經過總線來對這個數據加鎖。那麼其它線程就不能對這個數據進行讀寫操做。其實這樣的實現是有很大問題的,在多線程環境下,若是出現多個線程同時讀寫相同臨界量,那麼這種加鎖效率是很是低下的。
MESI它的工做原理能夠閱讀這篇文章 MESI--CPU緩存一致性協議
。
在內存系統中,處理器執行的程序指令有一部分是緩存在CPU緩存的,有一部分是須要在主存中獲取的。那麼,因爲處理器使用緩存和讀/寫緩衝區,這使得加載和存儲操做看上去多是在亂序執行。(能夠理解爲是有些指令讀寫操做不必定按照程序對處理器的順序要求來作,由於從緩存獲取指令進行操做,遠遠快於從主存獲取指令進行操做)。這就是做者理解的內存系統重排序。
若是兩個操做訪問同一個變量,且這兩個操做中有一個爲寫操做,此時這兩個操做之間就存在數據依賴性。數據依賴分下列三種類型:
寫一個變量以後,在讀這個變量。好比:a=1, b=a
寫一個變量後,再寫這個變量。好比a=1, a=2
讀一個變量後,再寫這個變量。好比:a=b, b=1
上面三種狀況,只要重排序兩個操做的執行順序,程序的執行結果將會被改變。前面提到過,編譯器和處理器可能會對操做作重排序。編譯器和處理器在重排序時,會遵照數據依賴性,編譯器和處理器不會改變存在數據依賴關係的兩個操做的執行順序。注意,這裏所說的數據依賴性僅針對單個處理器中執行的指令序列和單個線程中執行的操做,不一樣處理器之間和不一樣線程之間的數據依賴性不被編譯器和處理器考
慮。(言外之意就是數據依賴性不保證線程安全問題)
as-if-serial 語義的意思指
無論怎麼重排序(編譯器和處理器爲了提升並行度), (單線程)程序的執行結果不能被改變。編譯器,runtime 和處理器都必須遵照 as-if-serial 語義。
爲了遵照 as-if-serial 語義,編譯器和處理器不會對存在數據依賴關係的操做作重排序,由於這種重排序會改變執行結果。可是,若是操做之間不存在數據依賴關係,這些操做就可能被編譯器和處理器重排序。
這篇文章和你們一塊兒分析了重排序的三種方式和基本原理,又講了數據依賴性的必要性以及as-if-serial語義的用途。你們掌握了這些就能夠了,不必再深究重排序的知識了。
總之,在不影響程序執行結果的前提下,重排序是爲了加速程序指令執行速度。重排序只對單個線程內的程序指令執行結果不產生影響,可是多線程模式下,就算不存在數據依賴的指令,在重排序後有可能會影響程序的執行結果。