轉:
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,影響到併發性能。