cpu指令重排序的原理

2022-06-05 03:09:07 字數 2262 閱讀 1725

目錄:

1.重排序場景

2.追根溯源

3.快取一致性協議

4.重排序原因

一、重排序場景

class

resortdemo

public

void

reader()

}}

當兩個執行緒 a 和 b,a 首先執行writer() 方法,隨後 b 執行緒接著執行 reader() 方法。執行緒b在執行操作4時,能否看到執行緒 a 在操作1對共享變數 a 的寫入?

答案是:不一定能看到。

由於操作1和操作2沒有資料依賴關係,編譯器和處理器可以對這兩個操作重排序;同樣,操作3和操作4沒有資料依賴關係,編譯器和處理器也可以對這兩個操作重排序。

二、追根溯源

為了提公升計算效能,cpu 從單核公升級到了多核甚至用到了超執行緒技術最大化提高 cpu 的處理效能。cpu增加了快取記憶體,作業系統增加了程序、執行緒,通過cpu時間片的切換最大化的提公升cpu的使用率。

通過快取記憶體的儲存互動很好的解決了處理器與記憶體的速度矛盾,但是也為計算機系統帶來了更高的複雜度,因為它引入了乙個新的問題,快取一致性。

三、快取一致性協議

同乙份資料可能會被快取到多個 cpu 中,如果在不同 cpu 中執行的不同執行緒看到同乙份記憶體的快取值不一樣就會存在快取不一致的問題。為了達到資料訪問的一致,需要各個處理器在訪問快取時遵循一些協議,在讀寫時根據協議來操作,常見的協議有msi,mesi,mosi 等。最常見的就是 mesi 協議。

接下來給大家簡單講解一下 mesi。

mesi 表示快取行的四種狀態,分別是

1. m(modify) 表示共享資料只快取在當前 cpu 快取中,

並且是被修改狀態,也就是快取的資料和主記憶體中的數

據不一致

2. e(exclusive) 表示快取的獨佔狀態,資料只快取在當前

cpu 快取中,並且沒有被修改

3. s(shared) 表示資料可能被多個 cpu 快取,並且各個快取中的資料和主記憶體資料一致

4. i(invalid) 表示快取已經失效

對於 mesi 協議,從 cpu 讀寫角度來說會遵循以下原則:

cpu 讀請求:快取處於 m、e、s 狀態都可以被讀取,i 狀態 cpu 只能從主存中讀取資料。

cpu 寫請求:快取處於 m、e 狀態才可以被寫。對於 s 狀態的寫,需要將其他 cpu 中快取行置為無效才可寫。

四、重排序原因

mesi 協議雖然可以實現快取的一致性,但是也會存在一些問題。

基於上圖中的原因,cpu又引入了storebuffers的緩衝區。cpu0 只需要在寫入共享資料時,直接把資料寫入到 storebufferes 中,同時傳送 invalidate 訊息,然後繼續去處理其

他指令。當收到其他所有 cpu 傳送了 invalidate acknowledge 訊息時,再將 store bufferes 中的資料資料儲存至 cache line中。最後再從快取行同步到主記憶體。        

這個時候,我們再來看上述標題一中的重排序場景。

class resortdemo 

public void reader() }}

當執行1操作時,a的狀態從s->m,此時,執行緒a會先把變更寫入到storebuffers,然後傳送invalidate去非同步通知其他cpu執行緒,緊接著就執行了下面的2操作。

此時,可能1的變更還在storebuffers中,並未提交到主記憶體。什麼時候會提交到主記憶體,也不確定。

所以,執行緒b呼叫read方法可能會出現,看到了flag的變更,但是看不到a的變更,就出現了重排序的現象。

CPU指令重排序

cpu的速度至少比記憶體快100倍,為了提公升效率,會打亂原來的執行效率,會在一條指令執行過程中 比如去記憶體讀資料,大概慢100多倍 去同時執行另一條指令 前提是兩條指令沒有依賴關係 體現在 層面 就是,寫在後面的 可能比前面的 先執行。觀察下面 測試指令重排序 public class reor...

指令重排的原理

編譯器優化重排序和指令級並行重排序不會影響程式的結果,因此程式設計師需要著重處理的是記憶體系統重排序帶來的問題。1.編譯器優化的重排 編譯器在不改變單執行緒程式語義的前提下,可以重新安排語句的執行順序 2.指令級並行的重排 為了提高cpu的執行效率,現代的cpu基本上都支援指令流水線。2.1 指令流...

從JVM併發看CPU記憶體指令重排序

這兩天,我拜讀了 dennis byrne 寫的一片博文memory barriers and jvm concurrency 中譯文記憶體屏障與jvm併發 文中提到 對主存的一次訪問一般花費硬體的數百次時鐘週期。處理器通過快取 caching 能夠從數量級上降低記憶體延遲的成本這些快取為了效能重新...