前言
大家好,我是小彭锄列。
在上一篇文章里图云,我們聊到了 CPU 的三級(jí)緩存結(jié)構(gòu),提到 CPU 緩存就一定會(huì)聊到 CPU 的緩存一致性問題邻邮。那么竣况,什么是緩存一致性問題,CPU Cache 的讀取和寫入過程是如何執(zhí)行的筒严,MESI 緩存一致性協(xié)議又是什么丹泉?今天我們將圍繞這些問題展開。
學(xué)習(xí)路線圖:
1. 回顧 CPU 三級(jí)緩存結(jié)構(gòu)
由于 CPU 和內(nèi)存的速度差距太大鸭蛙,為了拉平兩者的速度差摹恨,現(xiàn)代計(jì)算機(jī)會(huì)在兩者之間插入一塊速度比內(nèi)存更快的高速緩存,CPU 緩存是分級(jí)的娶视,有 L1 / L2 / L3 三級(jí)緩存晒哄。
由于單核 CPU 的性能遇到瓶頸(主頻與功耗的矛盾),芯片廠商開始在 CPU 芯片里集成多個(gè) CPU 核心肪获,每個(gè)核心有各自的 L1 / L2 緩存寝凌。 其中 L1 / L2 緩存是核心獨(dú)占的,而 L3 緩存是多核心共享的孝赫。
基于局部性原理的應(yīng)用硫兰,CPU Cache 在讀取內(nèi)存數(shù)據(jù)時(shí),每次不會(huì)只讀一個(gè)字或一個(gè)字節(jié)寒锚,而是一塊塊地讀取劫映,每一小塊數(shù)據(jù)也叫 CPU 緩存行(CPU Cache Line)违孝。 為了標(biāo)識(shí) Cache 塊中的數(shù)據(jù)是否已經(jīng)從內(nèi)存中讀取,需要在 Cache 塊上增加一個(gè) 有效位(Valid bit)泳赋。
無論對(duì) Cache 數(shù)據(jù)檢查雌桑、讀取還是寫入,CPU 都需要知道訪問的內(nèi)存數(shù)據(jù)映射在 Cache 上的哪個(gè)位置祖今,這就是 Cache - 內(nèi)存地址映射問題校坑,映射方案有直接映射、全相聯(lián)映射和組相聯(lián)映射 3 種方案千诬。當(dāng)緩存塊滿或者內(nèi)存塊映射的緩存塊位置被占用時(shí)耍目,就需要使用 替換策略 將舊的 Cache 塊換出騰出空閑位置。
Cache - 內(nèi)存的直接映射方案
基于以上結(jié)構(gòu)徐绑,就會(huì)存在緩存一致性問題邪驮。
2. 什么是 CPU 緩存一致性問題?
CPU 緩存一致性(Cache Coherence)問題指 CPU Cache 與內(nèi)存的不一致性問題傲茄。事實(shí)上毅访, 在分析緩存一致性問題時(shí),考慮 L1 / L2 / L3 的多級(jí)緩存沒有意義盘榨, 所以我們提出緩存一致性抽象模型喻粹,只考慮核心獨(dú)占的緩存。
CPU 三級(jí)緩存與抽象模型
在單核 CPU 中草巡,只需要考慮 Cache 與內(nèi)存的一致性守呜。但是在多核 CPU 中,由于每個(gè)核心都有一份獨(dú)占的 Cache山憨,就會(huì)存在一個(gè)核心修改數(shù)據(jù)后查乒,兩個(gè)核心 Cache 數(shù)據(jù)不一致的問題。因此萍歉,我認(rèn)為 CPU 的緩存一致性問題應(yīng)該從 2 個(gè)維度理解:
- 縱向:Cache 與內(nèi)存的一致性問題: 在修改 Cache 數(shù)據(jù)后,如何同步回內(nèi)存档桃?
- 橫向:多核心 Cache 的一致性問題: 在一個(gè)核心修改 Cache 數(shù)據(jù)后枪孩,如何同步給其他核心 Cache?
接下來藻肄,我們將圍繞這兩個(gè)問題展開蔑舞。
3. 縱向:Cache 與內(nèi)存的一致性問題
3.1 CPU Cache 的讀取過程
這一節(jié),我們先來討論 Cache 的讀取過程嘹屯。事實(shí)上攻询,Cache 的讀取過程會(huì)受到 Cache 的寫入策略影響,我們暫且用相對(duì)簡(jiǎn)單的 “寫直達(dá)策略” 的讀取過程:
1州弟、CPU 在訪問內(nèi)存地址時(shí)钧栖,會(huì)先檢查該地址的數(shù)據(jù)是否已經(jīng)加載到 Cache 中(Valid bit 是否為 1)低零;
2、如果數(shù)據(jù)在 Cache 中拯杠,則直接讀取 Cache 塊上的字到 CPU 中掏婶;
-
3、如果數(shù)據(jù)不在 Cache 中:
- 3.1 如果 Cache 已裝滿或者 Cache 塊被占用潭陪,先執(zhí)行替換策略雄妥,騰出空閑位置;
- 3.2 訪問內(nèi)存地址依溯,并將內(nèi)存地址所處的整個(gè)內(nèi)存塊寫入到映射的 Cache 塊中老厌;
- 3.3 讀取 Cache 塊上的字到 CPU 中。
讀取過程(以寫直達(dá)策略)
但是黎炉,CPU 不僅會(huì)讀取 Cache 數(shù)據(jù)枝秤,還會(huì)修改 Cache 數(shù)據(jù),這就是第 1 個(gè)一致性問題 —— 在修改 Cache 數(shù)據(jù)后拜隧,如何同步回內(nèi)存宿百?有 2 種寫入策略:
3.2 寫直達(dá)策略(Write-Through)
寫直達(dá)策略是解決 Cache 與內(nèi)存一致性最簡(jiǎn)單直接的方式: 在每次寫入操作中,同時(shí)修改 Cache 數(shù)據(jù)和內(nèi)存數(shù)據(jù)洪添,始終保持 Cache 數(shù)據(jù)和內(nèi)存數(shù)據(jù)一致:
- 1垦页、如果數(shù)據(jù)不在 Cache 中,則直接將數(shù)據(jù)寫入內(nèi)存干奢;
- 2痊焊、如果數(shù)據(jù)已經(jīng)加載到 Cache 中,則不僅要將數(shù)據(jù)寫入 Cache忿峻,還要將數(shù)據(jù)寫入內(nèi)存薄啥。
寫直達(dá)的優(yōu)點(diǎn)和缺點(diǎn)都很明顯:
- 優(yōu)點(diǎn): 每次讀取操作就是純粹的讀取,不涉及對(duì)內(nèi)存的寫入操作逛尚,讀取速度更快垄惧;
- 缺點(diǎn): 每次寫入操作都需要同時(shí)寫入 Cache 和寫入內(nèi)存,在寫入操作上失去了 CPU 高速緩存的價(jià)值绰寞,需要花費(fèi)更多時(shí)間到逊。
寫直達(dá)策略
3.3 寫回策略(Write-Back)
既然寫直達(dá)策略在每次寫入操作都會(huì)寫內(nèi)存,那么有沒有什么辦法可以減少寫回內(nèi)存的次數(shù)呢滤钱?這就是寫回策略:
1觉壶、寫回策略會(huì)在每個(gè) Cache 塊上增加一個(gè) “臟(Dirty)” 標(biāo)記位 ,當(dāng)一個(gè) Cache 被標(biāo)記為臟時(shí)件缸,說明它的數(shù)據(jù)與內(nèi)存數(shù)據(jù)是不一致的铜靶;
2、在寫入操作時(shí)他炊,我們只需要修改 Cache 塊并將其標(biāo)記為臟争剿,而不需要寫入內(nèi)存已艰;
-
3、那么秒梅,什么時(shí)候才將臟數(shù)據(jù)寫回內(nèi)存呢旗芬?—— 就發(fā)生在 Cache 塊被替換出去的時(shí)候:
- 3.1 在寫入操作中,如果目標(biāo)內(nèi)存塊不在 Cache 中捆蜀,需要先將內(nèi)存塊數(shù)據(jù)讀取到 Cache 中疮丛。如果替換策略換出的舊 Cache 塊是臟的,就會(huì)觸發(fā)一次寫回內(nèi)存操作辆它;
- 3.2 在讀取操作中誊薄,如果目標(biāo)內(nèi)存塊不在 Cache 中,且替換策略換出的舊 Cache 塊是臟的锰茉,就會(huì)觸發(fā)一次寫回內(nèi)存操作呢蔫;
可以看到,寫回策略只有當(dāng)一個(gè) Cache 數(shù)據(jù)將被替換出去時(shí)判斷數(shù)據(jù)的狀態(tài)飒筑,“清(未修改過片吊,數(shù)據(jù)與內(nèi)存一致)” 的 Cache 塊不需要寫回內(nèi)存,“臟” 的 Cache 塊才需要寫回內(nèi)存协屡。這個(gè)策略能夠減少寫回內(nèi)存的次數(shù)俏脊,性能會(huì)比寫直達(dá)更高。當(dāng)然肤晓,寫回策略在讀取的時(shí)候爷贫,有可能不是純粹的讀取了,因?yàn)檫€可能會(huì)觸發(fā)一次臟 Cache 塊的寫入补憾。
這里還有一個(gè)設(shè)計(jì): 在目標(biāo)內(nèi)存塊不在 Cache 中時(shí)漫萄,寫直達(dá)策略會(huì)直接寫入內(nèi)存。而寫回策略會(huì)先把數(shù)據(jù)讀取到 Cache 中再修改 Cache 數(shù)據(jù)盈匾,這似乎有點(diǎn)多余腾务?其實(shí)還是為了減少寫回內(nèi)存的次數(shù)。雖然在未命中時(shí)會(huì)增加一次讀取操作削饵,但后續(xù)重復(fù)的寫入都能命中緩存岩瘦。否則,只要一直不讀取數(shù)據(jù)葵孤,寫回策略的每次寫入操作還是需要寫入內(nèi)存担钮。
寫回策略
通過寫直達(dá)或?qū)懟夭呗猿髟覀円呀?jīng)能夠解決 “在修改 Cache 數(shù)據(jù)后尤仍,如何同步回內(nèi)存” 的問題。接下來狭姨,我們來討論第 2 個(gè)緩存一致性問題 —— 在一個(gè)核心修改 Cache 數(shù)據(jù)后宰啦,如何同步給其他核心 Cache苏遥?
4. 橫向:多核心 Cache 的一致性問題
在單核 CPU 中,我們通過寫直達(dá)策略或?qū)懟夭呗员3至薈ache 與內(nèi)存的一致性赡模。但是在多核 CPU 中田炭,由于每個(gè)核心都有一份獨(dú)占的 Cache,就會(huì)存在一個(gè)核心修改數(shù)據(jù)后漓柑,兩個(gè)核心 Cache 不一致的問題教硫。
舉個(gè)例子:
1、Core 1 和 Core 2 讀取了同一個(gè)內(nèi)存塊的數(shù)據(jù)辆布,在兩個(gè) Core 都緩存了一份內(nèi)存塊的副本瞬矩。此時(shí),Cache 和內(nèi)存塊是一致的锋玲;
-
2景用、Core 1 執(zhí)行內(nèi)存寫入操作:
2.1 在寫直達(dá)策略中,新數(shù)據(jù)會(huì)直接寫回內(nèi)存惭蹂,此時(shí)伞插,Cache 和內(nèi)存塊一致。但由于之前 Core 2 已經(jīng)讀過這塊數(shù)據(jù)盾碗,所以 Core 2 緩存的數(shù)據(jù)還是舊的媚污。此時(shí),Core 1 和 Core 2 不一致置尔;
2.2 在寫回策略中杠步,新數(shù)據(jù)會(huì)延遲寫回內(nèi)存,此時(shí) Cache 和內(nèi)存塊不一致榜轿。不管 Core 2 之前有沒有讀過這塊數(shù)據(jù)幽歼,Core 2 的數(shù)據(jù)都是舊的鹦牛。此時(shí)返顺,Core 1 和 Core 2 不一致怜俐。
3茶敏、由于 Core 2 無法感知到 Core 1 的寫入操作葱峡,如果繼續(xù)使用過時(shí)的數(shù)據(jù)织鲸,就會(huì)出現(xiàn)邏輯問題默垄。
多核 Cache 不一致
可以看到:由于兩個(gè)核心的工作是獨(dú)立的型檀,在一個(gè)核心上的修改行為不會(huì)被其它核心感知到砸烦,所以不管 CPU 使用寫直達(dá)策略還是寫回策略弃鸦,都會(huì)出現(xiàn)緩存不一致問題。 所以幢痘,我們需要一種機(jī)制唬格,將多個(gè)核心的工作聯(lián)合起來,共同保證多個(gè)核心下的 Cache 一致性,這就是緩存一致性機(jī)制购岗。
4.1 寫傳播 & 事務(wù)串行化
緩存一致性機(jī)制需要解決的問題就是 2 點(diǎn):
特性 1 - 寫傳播(Write Propagation): 每個(gè) CPU 核心的寫入操作汰聋,需要傳播到其他 CPU 核心;
特性 2 - 事務(wù)串行化(Transaction Serialization): 各個(gè) CPU 核心所有寫入操作的順序喊积,在所有 CPU 核心看起來是一致烹困。
第 1 個(gè)特性解決了 “感知” 問題,如果一個(gè)核心修改了數(shù)據(jù)乾吻,就需要同步給其它核心髓梅,很好理解。但只做到同步還不夠绎签,如果各個(gè)核心收到的同步信號(hào)順序不一致女淑,那最終的同步結(jié)果也會(huì)不一致。
舉個(gè)例子:假如 CPU 有 4 個(gè)核心辜御,Core 1 將共享數(shù)據(jù)修改為 1000鸭你,隨后 Core 2 將共享數(shù)據(jù)修改為 2000。在寫傳播下擒权,“修改為 1000” 和 “修改為 2000” 兩個(gè)事務(wù)會(huì)同步到 Core 3 和 Core 4袱巨。但是,如果沒有事務(wù)串行化碳抄,不同核心收到的事務(wù)順序可能是不同的愉老,最終數(shù)據(jù)還是不一致。
非事務(wù)串行化
4.2 總線嗅探 & 總線仲裁
寫傳播和事務(wù)串行化在 CPU 中是如何實(shí)現(xiàn)的呢剖效?—— 此處隆重請(qǐng)出計(jì)算機(jī)總線系統(tǒng)嫉入。
寫傳播 - 總線嗅探: 總線除了能在一個(gè)主模塊和一個(gè)從模塊之間傳輸數(shù)據(jù),還支持一個(gè)主模塊對(duì)多個(gè)從模塊寫入數(shù)據(jù)璧尸,這種操作就是廣播咒林。要實(shí)現(xiàn)寫傳播,其實(shí)就是將所有的讀寫操作廣播到所有 CPU 核心爷光,而其它 CPU 核心時(shí)刻監(jiān)聽總線上的廣播垫竞,再修改本地的數(shù)據(jù);
事務(wù)串行化 - 總線仲裁: 總線的獨(dú)占性要求同一時(shí)刻最多只有一個(gè)主模塊占用總線蛀序,天然地會(huì)將所有核心對(duì)內(nèi)存的讀寫操作串行化欢瞪。如果多個(gè)核心同時(shí)發(fā)起總線事務(wù),此時(shí)總線仲裁單元會(huì)對(duì)競(jìng)爭(zhēng)做出仲裁徐裸,未獲勝的事務(wù)只能等待獲勝的事務(wù)處理完成后才能執(zhí)行遣鼓。
提示: 寫傳播還有 “基于目錄(Directory-base)” 的實(shí)現(xiàn)方案。
基于總線嗅探和總線仲裁重贺,現(xiàn)代 CPU 逐漸形成了各種緩存一致性協(xié)議骑祟,例如 MESI 協(xié)議宫补。
4.3 MESI 協(xié)議
MESI 協(xié)議其實(shí)是 CPU Cache 的有限狀態(tài)機(jī),一共有 4 個(gè)狀態(tài)(MESI 就是狀態(tài)的首字母):
- M(Modified曾我,已修改): 表明 Cache 塊被修改過,但未同步回內(nèi)存健民;
- E(Exclusive抒巢,獨(dú)占): 表明 Cache 塊被當(dāng)前核心獨(dú)占,而其它核心的同一個(gè) Cache 塊會(huì)失效秉犹;
- S(Shared蛉谜,共享): 表明 Cache 塊被多個(gè)核心持有且都是有效的;
- I(Invalidated崇堵,已失效): 表明 Cache 塊的數(shù)據(jù)是過時(shí)的型诚。
在 “獨(dú)占” 和 “共享” 狀態(tài)下,Cache 塊的數(shù)據(jù)是 “清” 的鸳劳,任何讀取操作可以直接使用 Cache 數(shù)據(jù)涵紊;
在 “已失效” 和 “已修改” 狀態(tài)下摸柄,Cache 塊的數(shù)據(jù)是 “臟” 的,它們和內(nèi)存的數(shù)據(jù)都可能不一致既忆。在讀取或?qū)懭?“已失效” 數(shù)據(jù)時(shí)驱负,需要先將其它核心 “已修改” 的數(shù)據(jù)寫回內(nèi)存,再從內(nèi)存讀然脊汀跃脊;
在 “共享” 和 “已失效” 狀態(tài)匾乓,核心沒有獲得 Cache 塊的獨(dú)占權(quán)(鎖)。在修改數(shù)據(jù)時(shí)不能直接修改又谋,而是要先向所有核心廣播 RFO(Request For Ownership)請(qǐng)求 拼缝,將其它核心的 Cache 置為 “已失效”,等到獲得回應(yīng) ACK 后才算獲得 Cache 塊的獨(dú)占權(quán)任斋。這個(gè)獨(dú)占權(quán)這有點(diǎn)類似于開發(fā)語言層面的鎖概念继阻,在修改資源之前,需要先獲取資源的鎖;
在 “已修改” 和 “獨(dú)占” 狀態(tài)下瘟檩,核心已經(jīng)獲得了 Cache 塊的獨(dú)占權(quán)(鎖)抹缕。在修改數(shù)據(jù)時(shí)不需要向總線發(fā)送廣播,能夠減輕總線的通信壓力墨辛。
事實(shí)上卓研,完整的 MESI 協(xié)議更復(fù)雜,但我們沒必要記得這么細(xì)睹簇。我們只需要記住最關(guān)鍵的 2 點(diǎn):
關(guān)鍵 1 - 阻止同時(shí)有多個(gè)核心修改的共享數(shù)據(jù): 當(dāng)一個(gè) CPU 核心要求修改數(shù)據(jù)時(shí)奏赘,會(huì)先廣播 RFO 請(qǐng)求獲得 Cache 塊的所有權(quán),并將其它 CPU 核心中對(duì)應(yīng)的 Cache 塊置為已失效狀態(tài)太惠;
關(guān)鍵 2 - 延遲回寫: 只有在需要的時(shí)候才將數(shù)據(jù)寫回內(nèi)存磨淌,當(dāng)一個(gè) CPU 核心要求訪問已失效狀態(tài)的 Cache 塊時(shí),會(huì)先要求其它核心先將數(shù)據(jù)寫回內(nèi)存凿渊,再從內(nèi)存讀取梁只。
提示: MESI 協(xié)議在 MSI 的基礎(chǔ)上增加了 E(獨(dú)占)狀態(tài),以減少只有一份緩存的寫操作造成的總線通信埃脏。
MESI 協(xié)議有一個(gè)非常 nice 的在線體驗(yàn)網(wǎng)站敛纲,你可以對(duì)照文章內(nèi)容,在網(wǎng)站上操作指令區(qū)剂癌,并觀察內(nèi)存和緩存的數(shù)據(jù)和狀態(tài)變化淤翔。網(wǎng)站地址:https://www.scss.tcd.ie/Jeremy.Jones/VivioJS/caches/MESI.htm
MESI 協(xié)議在線模擬
4.4 寫緩沖區(qū) & 失效隊(duì)列
MESI 協(xié)議保證了 Cache 的一致性,但完全地遵循協(xié)議會(huì)影響性能佩谷。 因此旁壮,現(xiàn)代的 CPU 會(huì)在增加寫緩沖區(qū)和失效隊(duì)列將 MESI 協(xié)議的請(qǐng)求異步化,以提高并行度:
- 寫緩沖區(qū)(Store Buffer)
由于在寫入操作之前谐檀,CPU 核心 1 需要先廣播 RFO 請(qǐng)求獲得獨(dú)占權(quán)抡谐,在其它核心回應(yīng) ACK 之前,當(dāng)前核心只能空等待桐猬,這對(duì) CPU 資源是一種浪費(fèi)麦撵。因此,現(xiàn)代 CPU 會(huì)采用 “寫緩沖區(qū)” 機(jī)制:寫入指令放到寫緩沖區(qū)后并發(fā)送 RFO 請(qǐng)求后溃肪,CPU 就可以去執(zhí)行其它任務(wù)免胃,等收到 ACK 后再將寫入操作寫到 Cache 上。
- 失效隊(duì)列(Invalidation Queue)
由于其他核心在收到 RFO 請(qǐng)求時(shí)惫撰,需要及時(shí)回應(yīng) ACK羔沙。但如果核心很忙不能及時(shí)回復(fù),就會(huì)造成發(fā)送 RFO 請(qǐng)求的核心在等待 ACK厨钻。因此扼雏,現(xiàn)代 CPU 會(huì)采用 “失效隊(duì)列” 機(jī)制:先把其它核心發(fā)過來的 RFO 請(qǐng)求放到失效隊(duì)列坚嗜,然后直接返回 ACK,等當(dāng)前核心處理完任務(wù)后再去處理失效隊(duì)列中的失效請(qǐng)求诗充。
寫緩沖區(qū) & 失效隊(duì)列
事實(shí)上苍蔬,寫緩沖區(qū)和失效隊(duì)列破壞了 Cache 的一致性。 舉個(gè)例子:初始狀態(tài)變量 a 和變量 b 都是 0蝴蜓,現(xiàn)在 Core1 和 Core2 分別執(zhí)行這兩段指令碟绑,最終 x 和 y 的結(jié)果是什么?
Core1 指令
a = 1; // A1
x = b; // A2
Core2 指令
b = 2; // B1
y = a; // B2
我們知道在未同步的情況下励翼,這段程序可能會(huì)有多種執(zhí)行順序。不管怎么執(zhí)行辜荠,只要 2 號(hào)指令是在 1 號(hào)指令后執(zhí)行的汽抚,至少 x 或 y 至少一個(gè)有值。但是在寫緩沖區(qū)和失效隊(duì)列的影響下伯病,程序還有以意料之外的方式執(zhí)行:
執(zhí)行順序(先不考慮 CPU 超前流水線控制) | 結(jié)果 |
---|---|
A1 → A2 → B1 → B2 | x = 0, y = 1 |
A1 → B1 → A1 → B2 | x = 2, y = 1 |
B1 → B2 → A1 → A2 | x = 1, y = 0 |
B1 → A1 → B2 → A2 | x = 2, y = 1 |
A2 → B1 → B2 → A1(A1 與 A2 重排) | x = 0, y = 0 |
Core2 也會(huì)出現(xiàn)相同的情況造烁,不再贅述 | x = 0, y = 0 |
上圖。
寫緩沖區(qū)造成指令重排
可以看到:從內(nèi)存的視角看午笛,直到 Core1 執(zhí)行 A3 來刷新寫緩沖區(qū)惭蟋,寫操作 A1 才算真正執(zhí)行了。雖然 Core 的執(zhí)行順序是 A1 → A2 → B1 → B2药磺,但內(nèi)存看到的順序卻是 A2 → B1 → B2 → A1告组,變量 a 寫入沒有同步給對(duì)變量 a 的讀取,Cache 的一致性被破壞了癌佩。
5. 總結(jié)
-
1木缝、在 CPU Cache 的三級(jí)緩存中,會(huì)存在 2 個(gè)緩存一致性問題:
- 縱向 - Cache 與內(nèi)存的一致性問題: 在修改 Cache 數(shù)據(jù)后围辙,如何同步回內(nèi)存我碟?
- 橫向 - 多核心 Cache 的一致性問題: 在一個(gè)核心修改 Cache 數(shù)據(jù)后,如何同步給其他核心 Cache姚建?
-
2矫俺、Cache 與內(nèi)存的一致性問題有 2 個(gè)策略:
- 寫直達(dá)策略: 始終保持 Cache 數(shù)據(jù)和內(nèi)存數(shù)據(jù)一致,在每次寫入操作中都會(huì)寫入內(nèi)存掸冤;
- 寫回策略: 只有在臟 Cache 塊被替換出去的時(shí)候?qū)懟貎?nèi)存厘托,減少寫回內(nèi)存的次數(shù);
-
3稿湿、多核心 Cache 一致性問題需要滿足 2 點(diǎn)特性:
- 寫傳播(總線嗅探): 每個(gè) CPU 核心的寫入操作催烘,需要傳播到其他 CPU 核心;
- 事務(wù)串行化(總線仲裁): 各個(gè) CPU 核心所有寫入操作的順序缎罢,在所有 CPU 核心看起來是一致伊群。
4考杉、MESI 協(xié)議能夠滿足以上 2 點(diǎn)特性,通過 “已修改舰始、獨(dú)占崇棠、共享、已失效” 4 個(gè)狀態(tài)實(shí)現(xiàn)了 CPU Cache 的一致性丸卷;
5枕稀、現(xiàn)代 CPU 為了提高并行度,會(huì)在增加 寫緩沖區(qū) & 失效隊(duì)列 將 MESI 協(xié)議的請(qǐng)求異步化谜嫉, 從內(nèi)存的視角看就是指令重排萎坷,破壞了 CPU Cache 的一致性。
今天沐兰,我們主要討論了 CPU 的緩存一致性問題與對(duì)應(yīng)的緩存一致性協(xié)議哆档。這里有一個(gè)問題:既然 CPU 已經(jīng)實(shí)現(xiàn)了 MESI 協(xié)議,已經(jīng)在硬件層面實(shí)現(xiàn)了寫傳播和事務(wù)串行化住闯,為什么 Java 語言層面還需要定義 volatile
關(guān)鍵字呢瓜浸?豈不是多此一舉?
你可能會(huì)說因?yàn)閷懢彌_區(qū)和失效隊(duì)列破壞了 Cache 一致性比原。好插佛,那不考慮這個(gè)因素的話,還需要定義 volatile
關(guān)鍵字嗎量窘?這個(gè)問題我們?cè)?下一篇文章 展開討論雇寇,請(qǐng)關(guān)注。
參考資料
- 深入淺出計(jì)算機(jī)組成原理(第 37蚌铜、38谢床、39 講) —— 徐文浩 著,極客時(shí)間 出品
- 深入理解 Java 虛擬機(jī)(第 5 部分) —— 周志明 著
- Java 并發(fā)編程的藝術(shù)(第 1厘线、2识腿、3 章) —— 方騰飛 魏鵬 程曉明 著
- 計(jì)算機(jī)組成原理教程(第 7 章) —— 尹艷輝 王海文 邢軍 著
- 10 張圖打開 CPU 緩存一致性的大門 —— 小林 Coding 著
- CPU有緩存一致性協(xié)議(MESI),為何還需要 volatile —— 一角錢技術(shù) 著
- Cache Miss – What It Is and How to Reduce It —— Linda D. 著
- CPU cache —— Wikipedia
- CPU caches —— LWN.net
- Cache coherence —— Wikipedia
- Directory-based cache coherence —— Wikipedia
- MESI protocol —— Wikipedia