日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CPU缓存一致性协议MESI

發布時間:2024/1/23 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CPU缓存一致性协议MESI 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

吹劍出自《莊子》:“夫吹管也,猶有也;吹劍首者,而已矣。” 吹劍只能發出小聲,以示自謙。“并發吹劍錄”,表達的是筆者斗膽講一些并發編程有關的知識,由于涉及計算機體系架構,筆者才疏學淺,恐有錯漏,望諸位不吝賜教,吾定當改之。

CPU架構

緩存與主存

解讀緩存一致性(Cache Coherency),先看一下CPU的架構

圖示一個4核CPU,有三個級別的緩存,分為是L1 Cache(一級緩存)、L2 Cache(二級緩存)、L3 Cache(三級緩存)

其中一級緩存有兩部分組成:L1I Cache(一級指令緩存)和L1D Cache(一級數據緩存)。

越靠近CPU的緩存速度越快,單價也更昂貴。其中一級和二級如今都屬于片內緩存(在CPU核內,早期L2緩存是片外的)獨立歸屬給各個CPU,而三級緩存是CPU間共享的。

查詢緩存的時候也是由近及遠,優先從一級緩存去查找,找到就結束查找,找不到則再去二級緩存查找。二級緩存找不到去三級緩存查找。三級緩存還找不到就去主存(Main Memory)查找。這里說的主存,就是我們平常說的內存。

內存是DRAM(Dynamic RAM),緩存是SRAM(Static RAM)。

緩存行

CPU操作緩存的單位是”緩存行“(cacheline),也就是說如果CPU要讀一個變量x,那么其實是讀變量x所在的整個緩存行。

緩存行大小

好了,既然我們知道了CPU讀寫緩存的單位是緩存行,那么緩存行的大小是多少呢?

查看機器緩存行大小的方法有很多,在Linux上你可以查看如下文件確認緩存行大小:

# L1D Cache cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size# L1I Cache cat /sys/devices/system/cpu/cpu0/cache/index1/coherency_line_size# L2 Cache cat /sys/devices/system/cpu/cpu0/cache/index2/coherency_line_size# L3 Cache cat /sys/devices/system/cpu/cpu0/cache/index3/coherency_line_size

或者用getconf命令:

# L1D Cache getconf LEVEL1_DCACHE_LINESIZE# L1I Cache getconf LEVEL1_ICACHE_LINESIZE# L2 Cache getconf LEVEL2_CACHE_LINESIZE# L3 Cache getconf LEVEL3_CACHE_LINESIZE

一般會看到:64。表示的是64字節。

注意,單核CPU上,可能沒有L3緩存。比如我在騰訊云買的最低配云主機……

MESI

并發場景下(比如多線程)如果操作相同變量,如何保證每個核中緩存的變量是正確的值,這涉及到一些”緩存一致性“的協議。其中應用最廣的就是MESI協議(當然這并不是唯一的緩存一致性協議)。

狀態介紹

在緩存行的元信息中有一個Flag字段,它會表示4種狀態,分為對應如下所說的M、E、S、I狀態。【知乎的表格是真的丑!】

狀態描述
M(Modified)代表該緩存行中的內容被修改了,并且該緩存行只被緩存在該CPU中。這個狀態的緩存行中的數據和內存中的不一樣,在未來的某個時刻它會被寫入到內存中(當其他CPU要讀取該緩存行的內容時。或者其他CPU要修改該緩存對應的內存中的內容時
E(Exclusive)代表該緩存行對應內存中的內容只被該CPU緩存,其他CPU沒有緩存該緩存對應內存行中的內容。這個狀態的緩存行中的內容和內存中的內容一致。該緩存可以在任何其他CPU讀取該緩存對應內存中的內容時變成S狀態。或者本地處理器寫該緩存就會變成M狀態
S(Shared)該狀態意味著數據不止存在本地CPU緩存中,還存在別的CPU的緩存中。這個狀態的數據和內存中的數據是一致的。當其他CPU修改該緩存行對應的內存的內容時會使該緩存行變成 I 狀態
I(Invalid)代表該緩存行中的內容是無效的

總線嗅探機制

CPU和內存通過總線(BUS)互通消息。

CPU感知其他CPU的行為(比如讀、寫某個緩存行)就是是通過嗅探(Snoop)線性中其他CPU發出的請求消息完成的,有時CPU也需要針對總線中的某些請求消息進行響應。這被稱為”總線嗅探機制“。

這些消息類型分為請求消息和響應消息兩大類,細分為6小類。

【知乎的表格是真的丑!】

消息類型請求/響應描述
Read請求通知其他處理器和內存,當前處理器準備讀取某個數據。該消息內包含待讀取數據的內存地址
Read Response響應該消息內包含了被請求讀取的數據。該消息可能是主內存返回的,也可能是其他高速緩存嗅探到Read 消息返回的
Invalidate請求通知其他處理器刪除指定內存地址的數據副本(緩存行中的數據)。所謂“刪除”,其實就是更新下緩存行對應的FLAG(MESI那個)
Invalidate Acknowledge響應接收到Invalidate消息的處理器必須回復此消息,表示已經刪除了其高速緩存內對應的數據副本
Read Invalidate請求此消息為Read 和 Invalidate消息組成的復合消息,主要是用于通知其他處理器當前處理器準備更新一個數據了,并請求其他處理器刪除其高速緩存內對應的數據副本。接收到該消息的處理器必須回復Read Response 和 Invalidate Acknowledge消息
Writeback響應消息包含了需要寫入內存的數據和其對應的內存地址

狀態流轉

記憶要點

有些眼花繚亂,個人總結了一些要點,方便記憶。

  • I 狀態有5條外出的線(local read有兩種可能的狀態轉移)
    • 當其他CPU沒有這個緩存行時,當前CPU從內存取緩存行更新到Cache,并把狀態設置為E
    • 當其他CPU有這份數據時:
      • 如果其他CPU是M狀態,則同步其緩存到主存,然后兩個CPU狀態再變為S
      • 如果其他CPU是S或E,則兩個CPU狀態都變為S

?

  • MSE三個狀態都是有4條外出的線(對應4種操作,只會流轉到一個狀態)
  • 而想從其他狀態流轉到達E狀態,比較刁鉆。只能從?I 狀態進行local read,并且其他CPU沒有該緩存行數據時,三個限定條件(加粗部分)缺一不可。

舉例

假設CPU0、CPU1、CPU2、CPU3中有一個緩存行(包含變量x)都是S狀態。

此時CPU1要對變量x進行寫操作,這時候通過總線嗅探機制,CPU0、CPU2、CPU3中的緩存行會置為I狀態(無效),然后給CPU1發響應(Invalidate Acknowledge),收到全部響應后CPU1會完成對于變量x的寫操作,更新了CPU1內的緩存行為M狀態,但不會同步到內存中。

接著CPU0想要對變量x執行讀操作,卻發現本地緩存行是I狀態,就會觸發CPU1去把緩存行寫入(回寫)到內存中,然后CPU0再去主存中同步最新的值。

Store Buffer

當然前面的描述隱藏了一些細節,比如實際CPU1在執行寫操作,更新緩存行的時候,其實并不會等待其他CPU的狀態都置為I狀態,才去做些操作,這是一個同步行為,效率很低。當前的CPU都引入了Store Buffer(寫緩存器)技術,也就是在CPU和cache之間又加了一層buffer,在CPU執行寫操作時直接寫StoreBuffer,然后就忙其他事去了,等其他CPU都置為I之后,CPU1才把buffer中的數據寫入到緩存行中。

Invalidate Queue

看前面的描述,執行寫操作的CPU1很聰明啦,引入了store buffer不等待其他CPU中的對應緩存行失效就忙別的去了。而其他CPU也不傻,實際上他們也不會真的把緩存行置為I后,才給CPU0發響應。他們會寫入一個Invalidate Queue(無效化隊列),還沒把緩存置為I狀態就發送響應了。

后續CPU會異步掃描Invalidate Queue,將緩存置為I狀態。和Store Buffer不同的是,在CPU1后續讀變量x的時候,會先查Store Buffer,再查緩存。而CPU0要讀變量x時,則不會掃描Invalidate Queue,所以存在臟讀可能。

L3 Cache在MESI中的角色

L3 緩存是所有CPU共享的一個緩存。縱觀剛才描述的MESI,好像涉及的都是CPU內的緩存更新,不涉及L3緩存,那么L3緩存在MESI中扮演什么角色呢?

其實在常見的MESI的狀態流程描述中(我上文也是),所有提到”內存“的地方都是值得商榷的。比如我上一節舉的例子中,CPU0中某緩存行是I,CPU1 中是M。當CPU0想到執行local read操作時,就會觸發CPU1中的緩存寫入到內存中,然后CPU0從內存中取最新的緩存行。其實準確來講這里是不準確的,因為由于L3緩存的存在,這里其實是直接從L3緩存讀取緩存行,而不直接訪問內存。

個人猜測是如果描述MESI狀態流轉的時候引入L3緩存,會造成描述會極其復雜。所以一般的描述都好似有意地忽略了L3緩存。

尾聲

從CPU的底層視角切入并發編程,其實還有很多可以介紹,比如偽共享、內存屏障又或者SIMD。然而技術文章畢竟應該做到主次分明,不能貪多。試圖大包大攬,反而讓讀者難以明辨綱要。這類文章讀起來也過于枯燥,讀者大多以收藏代替閱讀……

所以更多相關文章請關注后續啦!當然前提是有人樂意閱讀的話,我會繼續更新的,感謝支持!

你也可以關注我的公眾號:編程往事。和我交個朋友!

?

參考資料

https://stackoverflow.com/questions/54282246/whats-l3-role-part-in-mesi-protocal

https://www.cnblogs.com/jiagoujishu/p/13799459.html

https://www.sohu.com/a/407346190_120647979

編輯于 02-20

總結

以上是生活随笔為你收集整理的CPU缓存一致性协议MESI的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。