CPU緩存機制 並發編程的基礎


CPU多核緩存架構

 

1、多線程環境下存在的問題

   在多處理器系統中,每個處理器都有自己的高速緩存,而它們又共享同一主內存(RAM)。基於高速緩存的存儲交互很好地解決了處理器與內存的速度矛盾,但是也引入了新的問題:緩存一致性(CacheCoherence)。

  若有兩個線程 T1 和 T2 都去計算 x + 1的值(x初始值為1),T1線程的由 CPU1去處理, T2 線程由CPU2去處理;CPU1和CPU2的高速緩存中的副本都是 x = 1,經過CPU加1操作后,再次放入的CPU1、CPU2的高速緩存中的數都為 x = 2 ,當數據放入到主內存中的時候,就引發了緩存不一致性的問題;

  為了解決一致性的問題,需要各個處理器訪問緩存時都遵循一些協議(緩存一致性協議),在讀寫時要根據協議來進行操作,這類協議有MSIMESI(IllinoisProtocol)、MOSI、Synapse、Firefly及DragonProtocol,等等。解決一致性的問題也可以使用總線加鎖的方式,當CPU1讀主內存同一段邏輯空間時,給總線加一把鎖,CPU2讀寫的時候都沒有辦法進行,這樣也可以解決該問題,但是這樣的效率太低,一般不使用這種方式

2、MESI緩存一致性協議  

CPU緩存的最小單位:緩存行(Cache line),有可能32字節、64字節、128字節,根據CPU來定;

(1)MESI的介紹

(2) MESI緩存一致性協議的工作原理

以上面多線程中計算 x 加1的操作為例;

(1)T1 從主存中讀取 x = 1,放到 CPU1 的緩存,狀態標記為獨占(E),並且 CPU1 時刻監聽總線當中其他CPU對這塊內存的操作(總線嗅探機制);

(2)若 T1 計算之后還沒有會寫到主存中,此時 T2 由CPU2計算x加1的操作,從主存中讀取x = 1,放入CPU2的緩存中;

(3)當 T2 通過總線從 主存中讀取了 x = 1,T1的CPU1通過總線嗅探機制知道了T2從主存中讀取了同塊內存,則將 CPU1 中的狀態修改為共享(S)

CPU2 中的狀態標記為共享(S),同時 CPU2 時刻監聽總線當中其他CPU對這塊內存的操作;

(4)此時,T1通過 CPU1 計算完成了的結果:x = 2,需要將結果回寫到主存中;首先鎖住CPU1的緩存行,將CPU1 的緩存的狀態標記為修改(M),接着發送消息給總線,其他的CPU一直在嗅探,嗅探到消息之后將其他的CPU的緩存狀態標記為無效(I),此時CPU2的緩存狀態被修改的無效;

(5)接着,CPU1 將計算結果 x = 2 回寫到主存中(主存中的數據此時變為 x = 2),接着CPU1 將緩存的狀態標記為獨占(E), 丟棄掉其他CPU緩存狀態為無效的數據;

(6)接着CPU2 重新從主存中讀取數據(x = 2),通過總線嗅探機制CPU1又嗅探到CPU2讀取了主存中的這塊內存區域,則將 CPU1的緩存狀態和CPU2的緩存狀態都設置為共享(S)....

失效指的是緩存行的失效,

若兩個CUP同一個時間都去修改主存中 x 的值,則在一個指令周期內會進行裁決,一個認為有效,另一個認為無效;有一個裁決為無效了,不一定再次去主存中讀取了,取決於程序的寫法;

比如在java中,變量前面增加 volatile 關鍵字,則在底層就去要遵守緩存一致性協議;

(3)什么情況下緩存一致性協議會失效?

情況一:

如果x 的存儲長度大於緩存行的存儲單元;數據存儲橫跨兩個以上的緩存行,沒有辦法去給緩存行去加鎖了,只能通過總線加鎖的方式;

情況二:

CPU本身不支持緩存一致性協議,比如早期的奔騰系列CPU;

3、指令重排序問題
  為了使得處理器內部的運算單元能盡量被充分利用,處理器可能會對輸入代碼進行亂序執行(Out-Of-Order Execution)優化,處理器會在計算之后將亂序執行的結果重組,保證該結果與順序執行的結果是一致的,但並不保證程序中各個語句計算的先后順序與輸入代碼中的順序一致。因此,如果存在一個計算任務依賴另一個計算任務的中間結果,那么其順序性並不能靠代碼的先后順序來保證。與處理器的亂序執行優化類似,Java虛擬機的即時編譯器中也有類似的指令重排序(Instruction Reorder)優化。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM