586以前的CPU, 會經過LOCK鎖總線的形式來實現原子操做. 686開始則提供了存儲一致性(Cache coherence), 這是多處理的基礎, 也是原子操做的基礎.git
1. 存儲的粒度編程
存儲的組織形式(粒度)是以CacheLine爲單位的, 一般爲64字節甚至更高(早期也有32字節的). 而後幾組CacheLine組成一個小的LRU(或者其餘替換規則).緩存
2. 協議服務器
存儲一致性(CC)通常是經過MESI協議, 以及後續的變種協議, 例如Intel的MESIF協議和AMD的MOESI協議, 來實現的. 多線程
以MESI協議爲例:架構
Modified: 獨佔CacheLine, 已經修改了, 可是還未同步到主存優化
Exclusive: 獨佔, 而且和主存一致線程
Shared : 共享的, 其餘core也擁有該CacheLine, 而且與主存中一致server
Invalid: 表示該CacheLine不可用對象
3. 通信
有了協議, 那麼就須要通信來實現協議(存儲的狀態). 通信有兩種, 一種是廣播/偵聽, 一種是目錄式.
廣播/偵聽顧名思義就是存儲狀態的變動, 會被廣播到其餘core上面去, 進而去維護CacheLine的狀態. 很明顯這種方式會浪費大量的流量, 並且難以擴展, CPU核數多了, 總線就是明顯的瓶頸.
目錄式, 就是把改變通知給具體的core, 從而避免廣播. 可是考慮一種極端狀況, 若是不少個core都在訪問同一個CacheLine, 那仍是不能避免(事實上的)廣播. 因此, 多線程編程時, 共享同一個CacheLine不是一個好的選擇.
有了上面的東西, 如今咱們來考慮原子操做的實現:
1. 原子的Load/Store
因爲CPU對緩存的管理是以CacheLine爲單位的, 因此在一個CacheLine內load/store實際上都是原子的. Load和Store一個8字節對象, 不可能高4位和低4位是分開操做的(從而搞成倆值).
可是光有這個實際上還不夠, CPU對CacheLine的修改不是當即寫到主存裏面去, 因此其餘Core看到的值就有多是老的值, 因此這時候還須要fence來讀到最新的值; 至於寫, 那必定須要寫權限, 即M或者E狀態, 而這兩個權限裏面都有最新的值(只是你剛纔讀到的不必定是最新的, 因此有可能用老值覆蓋了新值).
2. FetchAndAdd
這是比load和store稍微複雜的操做, 其實是一個複合操做. 可是有了M和E狀態, 就很好理解了:
lock(CacheLine) v := load(obj) v += add store(obj, v) release(CacheLine)
x86裏面是xadd指令.
3. CompareAndSwap
那麼CAS, 也就能夠猜出來:
lock(CacheLine) v := load(obj) if v != expected { store(obj, new_value) } release(CacheLine)
x86裏面是xchg
這裏說的lock和release均表示對該CacheLine獨佔和解出獨佔的意思.
關於原子操做的原理, 鮮有資料表表示其具體怎麼作的, 頗有多是過於偏向於硬件. 可是對MESI等協議的思考, 實際上仍是能猜到CPU內部的實現(至少七八不離十). 好在找到兩個資料, 一個是<<並行多核體系結構基礎>>和<<從鯤鵬920瞭解現代服務器實現和引用>>. 其中鯤鵬920內存模型章節這麼寫到:
原子指令在軟件上看來邏輯並不複雜,但在微架構上看,成本是很高的。若是咱們把CPU 和內存都看作是總線上的一個個獨立的實體,有一個CPU要作CAS指令,這個CPU須要先從 內存中讀一個值,同時要在內存控制器上設置一個標誌,保證其餘CPU寫不進去,等它比 較完了,而後再決定寫一個值回去,纔會讓其餘CPU寫入。
不一樣微架構實現有不一樣方法對行爲進行優化,在鯤鵬920上,原子指令的請求須要在 L3Cache上進行排隊,保證在原子操做的多個動做之間能維持原子指令要求的語義。這個 排隊自己也有成本。因此沒有原子須要就不要輕易用原子變量,這實際上是有成本的。
並行多核體系結構這麼寫到:
幸運的是, 緩存一致性協議提供了原子性被保障的基礎. 舉例來講, 當遇到一個原子指令時, 這個協議知道須要保證原子性. 他首先得到對存儲單元M的"獨家全部權" (經過將其餘包含M的緩存塊中的拷貝都置爲無效). 當得到獨家全部權以後, 這個協議會確保只有一個處理器可以訪問這個塊, 而若是其餘處理器在此時想要訪問的話就會經歷緩存缺失, 接下來原子指令就能夠執行. 在原子指令持續期間, 其餘處理器不容許"偷走"這個塊. 距離來講, 如通另外一個處理器要求讀或者寫這個塊, 這個塊就被"偷"了(如塊被清理, 塊的狀態被降級爲無效). 在原子指令完成以前暴露塊會破壞指令的原子性, ......
參考:
1) 並行多核體系結構基礎