CAS指令與MESI緩存一致性協議


CAS(Compare-And-Swap)指令是並行程序設計最基礎的基石,隨着越來越多的本本都用上了雙核,這個世界已經快速步入並行計算時代,CAS指令發揮的作用也就越來越大。CAS指令,在Intel CPU上稱爲CMPXCHG,的作用是將指定內存地址的內容與所給的某個值相比,如果相等,則將其內容替換爲所給的另一個值,這一系列操作是原子的,不可能被中斷。基本上所有的同步機制,與信號量、Java中的synchronized等的實現最終都要用到CAS指令,即使鎖無關的數據結構也離不開CAS指令。 

關於CAS指令最著名的傳聞是CAS需要鎖總線,因此CAS指令不但慢而且會嚴重影響系統併發度,即使沒有衝突是也一樣。不過在較新的CPU中(對於Intel CPU來說是486之後),事實並非如此。目前的CPU一般都採用了很好的緩存一致性協議,在很多情況下能夠防止鎖總線的發生,這其中最著名的就是Intel CPU中使用的MESI緩存一致性協議。 

先來說說緩存一致性問題。爲了提高數據訪問效率,每個CPU上都有一個容量很小(現在一般是1M這個數量級),速度很快的緩存,用於緩存最常訪問的那些數據。由於操作內存的速度實在太慢,數據被修改時也只更新緩存,並不直接寫出到內存中去,這一來就造成了緩存中的數據與內存不一致。如果系統中只有一個CPU,所有線程看到的都是緩存中的最新數據,當然沒問題。但如果系統中有多個CPU,同一份內存可能會被緩存到多個CPU中,如果在不同CPU中運行的不同線程看到同一份內存的緩存值不一樣就麻煩了,因此有必要維護這多種緩存的一致性。當然要做到這一點只要一有修改操作,就通知所有CPU更新緩存,或者放棄緩存下次訪問的時候再重新從內存中讀取。但這會Stupid的實現顯然不會有好的性能,爲解決這一問題,產生了很多維護緩存一致性的協議,MESI就是其中一種。 

MESI協議的名稱由來是指這一協議爲緩存的每個數據單位(稱爲cache line,在Intel CPU上一般是64字節)維護兩個狀態位,使得每個數據單位可能處於M、E、S或I這四種狀態之一。各種狀態含義如下: 

M: 被修改的。處於這一狀態的數據只在本CPU中有緩存,且其數據已被修改,沒有更新到內存中 
E: 獨佔的。處於這一狀態的數據只在本CPU中有緩存,且其數據沒有被修改,與內存一致 
S: 共享的。處於這一狀態的數據在多個CPU中有緩存 
I: 無效的。本CPU中的這份緩存已經無效了。 

當CPU要讀取數據時,只要緩存的狀態不是I都可以從緩存中讀,否則就要從主存中讀。這一讀操作可能會被某個處於M或E狀態的CPU截獲,該CPU將修改的數據寫出到內存,並將自己設爲S狀態後這一讀操作才繼續進行。只有緩存狀態是E或M時,CPU纔可以修改其中的數據,修改後緩存即處於M狀態。如果CPU要修改數據時發現其緩存不處於E或M狀態,則需要發出特殊的RFO指令(Read For Ownership),將其它CPU的緩存設爲I狀態。 

因此,如果一個變量在某段時間內只被一個線程頻繁修改,則對應的緩存早就處於M狀態,這時CAS操作就不會涉及到總線操作。所以頻繁的加鎖並不一定會影響系統併發度,關鍵是看鎖衝突的情況嚴重不嚴重,如果經常出現衝突,即緩存一會被這個CPU獨佔,一會被那個CPU獨佔,這時纔會不斷產生RFO,影響到併發性能。2.互鎖操作

————————————————————————————————————————————

適用lock指令前綴.雖然可以達到一個原子上的操作,但是這個機制操作的範圍小。
也就是說它是指令集的同步保護機制。可以達到64位的內存單元.

x86 處理器使用“lock”前綴的方式提供了在指令執行期間對總線加鎖的手段。
芯片上有一條引線 LOCK,如果在一條彙編指令(ADDADCANDBTCBTRBTSCMPXCHG, CMPXCH8B, DECINCNEGNOTORSBBSUBXOR,XADDXCHG)前加上"lock"前綴,經過彙編後的機器代碼就使得處理器執行該指令時把引線 LOCK 的電位拉低,從而把總線鎖住,這樣其它處理器或使用DMA的外設暫時無法通過同一總線訪問內存

從 P6 處理器開始,如果指令訪問的內存區域已經存在於處理器的內部緩存中,則“lock” 前綴並不將引線 LOCK 的電位拉低,而是鎖住本處理器的內部緩存,然後依靠緩存一致性協議保證操作的原子性.



發佈了97 篇原創文章 · 獲贊 1 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章