就為了一個原子操作,其他CPU核心罷工了
阿新 • • 發佈:2020-05-22
## i++問題
“阿Q趕快回去吧,隔壁二號車間的虎子說我們改了他們的資料,上門來鬧事了”
由於老K的突然出現,我不得不提前結束與小黑的交流,趕回了CPU一號車間。
見到我回來,虎子立刻朝我嚷嚷:“你們是怎麼回事?才幾納秒的時間,就把資料給我改了,你說這事怎麼辦吧!”
我聽著迷迷糊糊的,連連說到:“虎子你先別急,我剛回來,到底出什麼事兒了,先讓我瞭解清楚好不好?”
![](https://imgkr.cn-bj.ufileos.com/63c85e6d-cb63-4dfb-874a-1ae09329e416.png)
接下來,老K把事情的經過告訴了我。原來,我們兩個CPU車間各自負責的執行緒都在執行一個`i++`的操作,我們都把`i`的值放到了自己的快取中,完了之後都沒有通知對方,加了兩次但結果卻只有一次,出現了`資料不一致問題`。
## 原子操作
瞭解清楚事情的原委之後,我向虎子說道:“大家都執行一樣的程式碼,這事兒也不能怪我們啊”
虎子一聽急了,“怎麼不怪你們了,我們比你們先一步找記憶體拿走了i,那你們得等我們加完之後再用啊,不信你可以打電話問記憶體那傢伙,看看是不是我們二號車間先來的”
“好好好,你先冷靜一下,你看我們又不知道你們先去拿了,這不情有可原嗎,再說現在事情已經出了,我們應該一起坐下來想個辦法避免以後再次出現這種問題,你說是不是?”
虎子嘆了口氣問道:“那你說說你有什麼辦法?”
![](https://imgkr.cn-bj.ufileos.com/0c10bdea-9e07-4226-afd7-56b859ae2406.png)
我繼續說道:“你看啊,像咱們在執行`i++`這種操作的時候就不應該被幹擾”
“不被幹擾?”
“對,比如虎子你們二號車間在訪問i的時候,我們一號車間就不能訪問,需要等著,等你們訪問完成我們再來,非常簡單的辦法卻很有用”
虎子聽完一愣,“這不就是加鎖嗎?你是想怪程式設計師做i++前沒有加鎖?”
“的確是加鎖,不過這種簡單操作還要程式設計師來加鎖那也太麻煩了,咱們CPU內部處理好就行了”
“內部處理,你打算怎麼實現?”,虎子問到。
“這,,讓我想想···”,虎子問到了具體實現,我倒還沒想到這一步。
這時,一旁的老K站了出來:“我倒是有個辦法,可以找匯流排主任啊,他是負責協調各個車間使用系統匯流排訪問記憶體的總指揮,讓他在中間協調一下應該不難”
老K一語點醒夢中人,接著我們就去找了匯流排主任,後來我們商量出了一套解決方案:我們定義了一個叫`原子操作`的東西,表示這是一個不可切分的動作,誰要執行原子操作,匯流排主任就在系統總線上加上一個`LOCK#`訊號,其他車間的想去訪問記憶體就得等著,直到原子操作指令執行完畢。
![](https://imgkr.cn-bj.ufileos.com/e1564964-63ac-4bb8-83f3-2065dbc71bfc.png)
我們把這套方案上報了領導,很快就批下來了,後面我們8個車間都按照這套方案來工作,以後程式設計師們把i++這樣的動作換成原子操作後,問題就能迎刃而解。
不過施行了一段時間之後,各個車間卻開始大倒苦水:就因為某個車間要執行一個原子操作,就讓匯流排主任把系統匯流排鎖住,其他車間的人都沒法訪問記憶體,都幹不了活了,嚴重影響工作效率。
抱怨歸抱怨,在沒有更好的替代方案出現之前,日子還得過下去。
## 快取引發的問題
不過,沒過多久,資料不一致問題又一次出現了。
這一次,倒不是加法的問題,我們兩車間還是因為各自快取的原因,先後修改了變數的值,對方沒有即時知道,誤用了錯誤的值,以致釀成大錯。
![](https://imgkr.cn-bj.ufileos.com/f9acea83-a8f5-4a8f-b799-4856b2683027.png)
“阿Q,上次那辦法好是好,可解決不了這一次的問題啊”,虎子再次找上門來。
“你來的正好,我正想去找你說這事呢”
“哦,是嗎,難不成你想到破解之道了?”
“只是一些初步的想法,問題的核心在於現在咱們各個車間各自為政,都有自己的私有快取,各自修改資料後向記憶體更新時也不互相打招呼,缺少一個聯絡機制”
虎子點了點頭,“確實,所以咱們需要建立一個聯絡機制,來對各個車間的快取內容進行統一管理是嗎?”
“對!這事兒咱倆說了可不算,我建議召集8個核心車間的代表,統一開一個會議,詳細討論下這個問題。哦,對了,把匯流排主任也叫上,他經驗豐富說不定能提供一些思路”
## 快取一致性協議MESI
很快,咱們CPU的8個核心車間就為此問題召開了會議,並且取得了非常重要的成果。
我們牽了一條新的專線,把8個核心車間連線起來,用於各個車間之間進行資訊溝通,不同於CPU外部的匯流排系統,大家把這個叫`片內匯流排`。
![](https://imgkr.cn-bj.ufileos.com/47646823-9da7-4a96-b171-0a6c668ece10.png)
新的線路鋪設好了,以後大家就可以通過這條線路即時溝通,為了解決之前出現的問題,大家還制定了一套規則,叫做`快取一致性協議`。
規則裡面規定了所有車間的快取單元——`快取行`有四種狀態:
- 已修改Modified (M)
> 快取行已經被修改了,與記憶體的值不一樣。如果別的CPU核心要讀記憶體這塊資料,要趕在這之前把該快取行回寫到主存,把狀態變為共享(S).
- 獨佔Exclusive (E)
> 快取行只在當前CPU核心快取中,而且和記憶體中資料一樣。當別的CPU核心讀取它時,狀態變為共享;如果當前CPU核心修改了它,就要變為已修改狀態。
- 共享Shared (S)
> 快取行存在於多個CPU核心的快取中,而且和記憶體中的內容一致。
- 無效Invalid (I)
> 快取行是無效的
四種狀態之間的轉換是這樣的:
![](https://imgkr.cn-bj.ufileos.com/98fe189a-31db-4332-9d2e-003668597dda.png)
按照這套規則,大家不能再像以前那樣隨意了,各車間對自家快取進行讀寫時,都要相互通一下氣,避免使用過時的資料。
除此之外,還規定如果一塊記憶體區域被多個車間都快取,就不再允許多個車間同時去修改快取了。
會議還有另外一個收穫,以前被各車間詬病的每次原子操作都要鎖定匯流排,導致大家需要訪問記憶體的都只能乾等著的問題也得到了解決。以後匯流排主任不再需要鎖定匯流排了,通過這次的快取一致性協議就可以辦到。
自此以後,資料不一致的問題總算是根治了,咱們8個車間又可以愉快的工作了。
## 往期熱門回顧
[完了!CPU一味求快出事兒了!](https://mp.weixin.qq.com/s/5_JN7trS_lS3Nnw5u12p6g)
[可怕!CPU竟成了黑客的幫凶!](https://mp.weixin.qq.com/s/jo6pF4yQ8CU809M1dxo-Yw)
[雜湊表哪家強?幾大程式語言吵起來了!](https://mp.weixin.qq.com/s/h0FqX9AZByfpgUZrsRVTWg)
[核心地址空間大冒險4:執行緒切換](https://mp.weixin.qq.com/s/v6nc9aIBY_R1S6ToPzj5Qg)
[震撼!全網第一張原始碼分析全景圖揭祕Nginx](https://mp.weixin.qq.com/s/XrtH9-Eo7pzJu-Fzt89voQ)
[一個整數+1引發的災難](https://mp.weixin.qq.com/s/gZPxqZzY2rnngxvvzexWTw)
[一網打盡!每個程式猿都該瞭解的黑客技術大彙總](https://mp.weixin.qq.com/s/V7wBdl-5W4ehTAnACQFjGQ)
[DDoS攻擊:無限戰爭](https://mp.weixin.qq.com/s/JTr1-5nPtseAYXfvJdamVg)
[一個Java物件的回憶錄:垃圾回收](https://mp.weixin.qq.com/s/xp2S4_3UQTZ0TOIlVqM8uw)
[誰動了你的HTTPS流量?](https://mp.weixin.qq.com/s/lxpHhHVIh6DktoHzrRLaKA)
[路由器裡的廣告祕密](https://mp.weixin.qq.com/s/7gM31s4-hTJTprJnxsHgEA)
[一個HTTP資料包的奇幻之旅](https://mp.weixin.qq.com/s/suzicCzb2g5b8NN71S5Ngw)
[我是一個流氓軟體執行緒](https://mp.weixin.qq.com/s/-ggUa3aWkjjHjr9VwQL9TQ)
![](https://imgkr.cn-bj.ufileos.com/62b181b0-cb63-47a0-b836-131de3a562c7.png)
![](https://imgkr.cn-bj.ufileos.com/06d25f4e-bd38-404b-a901-173737bb7c