『壹』 緩存一致性指的是什麼
首先明白什麼是緩存,緩存是介於物理存儲與CPU處理之間的一段內存空間,主要用於存儲從物理存儲讀出、或者要寫入的數據,這需要硬體或者軟體支持。如果讀取或寫入物理存儲中的一個位元組或一段數據,如果沒有緩存,那麼每次的讀寫請求都會直接訪問物理存儲,而物理存儲的速度一般都比較慢,而且物理定位也比較慢,緩存使用後,可以一次性讀出需要的數據相鄰的數據,暫時存儲在緩存中,下面如果還要讀取,而這部分數據已經在緩存了,就不需要再去讀取物理存儲,同樣,如果是寫操作,可以先將需要寫入的數據暫時保存在緩存中,等到緩存過期或者強行清空時,再一次寫入物理存儲。這樣可以把多次的物理存儲訪問,變成一次物理存儲的訪問,提高訪問效率。具體的操作演算法這里不多作闡述。
緩存的一致性就是指緩存中的數據是否和目標存儲中的數據是一樣的,也就是說緩存中已經修改得數據是否已經保存到了物理存儲中,物理存儲中已經被修改得內容,是否與緩存的內容是一樣的。這就是一致性的概念。
『貳』 CPU寫Cache時內容不一致現象,有那兩種解決方法各自的優缺點是什麼
有兩種方法寫回法(抵觸修改法):是在CPU執行寫操作時,信息只寫入 Cache,僅當需要被替換時,才將已被寫入過的 Cache塊先送回主嫌橡存,然後再調入新塊。
寫直芹配旁達法(直達法):利用 Cache-主存存儲層次在處理機和主存之間的直接通路,每當處理機寫入 Cache的同時,也通過此通路直接寫入主存在可靠性上,寫直達法優於寫回法。
在與主存的通信量上,寫回法少於寫直達法;在控制的復雜性上,寫直達法比寫回法簡單;在硬體實現的代價上,寫回法要比寫直達法好。
(2)cpu緩存一致性協議缺點擴展閱讀:
由於cache的內容只是主存部分內容的拷貝,它應當與主存內容保持一致。但是,在一些情況下會出現cache和主存內容不一致的情況。如下:
1、 寫操作後,沒有刷洗cache到內存裡面,那麼cache為臟,跟內存不同步。
2、多CPU模式。 一個CPU修改了本地cache,那麼其它CPU的cache全部失效。
3、DMA訪問。DMA修改了內存中的值,cache中仍然為原賣弊值,錯誤。
『叄』 CPU Cache
title: CPU Cache
date: 2019-11-17 20:20:30
keywords: cache "CPU cache" "三級緩存" 緩存映射 cache原理 多級cache TLB
引入 Cache 的理論基礎是程序局部性原理,包括時間局部性和空間局部性。時間局部性原理即最近被CPU訪問的數據,短期內CPU 還要訪問(時間);空間局部性即被CPU訪問的數據附近的數據,CPU短期內還要訪問(空間)。因此如果將剛剛訪問過的數據緩存在一個速度比主存快得多的存儲中,那下次訪問時,可以直接從這個存儲中取,其速度可以得到數量級的提高。
CPU緩存是(Cache Memory)位於CPU與內存之間的臨時存儲器,它的容量比內存小但交換速度快。在緩存中的數據是內存中的一小部分,但這一小部分是短時間內CPU即將訪問的,當CPU調用大量數據時,就可避開內存直接從緩存中調用,從而加快讀取速度。
在CPU中加入緩存是一種高效的解決方案,是對於存儲器件成本更低,速度更快這兩個互相矛盾的目標的一個最優解決方案,這樣整個內存儲器(緩存+內存)就變成了既有緩存的高速度,又有內存的大容量的存儲系統了。緩存對CPU的性能影響很大,主要是因為CPU的數據交換順序和CPU與緩存間的帶寬引起的。
下圖是一個典型的存儲器層次結構,我們可以看到一共使用了三級緩存
各級存儲訪問延遲的對比
介於CPU和主存儲器間的高速小容量存儲器,由靜態存儲晶元SRAM組成,容量較小但比主存DRAM技術更加昂貴而快速, 接近於CPU的速度。CPU往往需要重復讀取同樣的數據塊, Cache的引入與緩存容量的增大,可以大幅提升CPU內部讀取數據的命中率,從而提高系統性能。通常由高速存儲器、聯想存儲器、地址轉換部件、替換部件等組成。如圖所示。
早期採用外部(Off-chip)Cache,不做在CPU內而是獨立設置一個Cache。現在採用片內(On-chip)Cache,將Cache和CPU作在一個晶元上,且採用多級Cache,同時使用L1 Cache和L2 Cache,甚至有L3 Cache。
上圖顯示了最簡單的緩存配置。它對應著最早期使用CPU cache的系統的架構。CPU內核不再直接連接到主內存。所有的數據載入和存儲都必須經過緩存。CPU核心與緩存之間的連接是一種特殊的快速連接。在一個簡化的表示中,主存和高速緩存連接到系統匯流排,該系統匯流排也可用於與系統的其他組件進行通信。我們引入了系統匯流排(現代叫做「FSB」)。
引入緩存後不久,系統變得更加復雜。高速緩存和主存之間的速度差異再次增大,使得另一個級別的高速緩存不得不被添加進來,它比第一級高速緩存更大且更慢。出於經濟原因,僅增加第一級緩存的大小不是一種選擇。今天,甚至有機器在生產環境中使用了三級緩存。帶有這種處理器的系統如圖下所示。隨著單個CPU的內核數量的增加,未來的緩存級別數量可能會增加。現在已經出現了擁有四級cache的處理器了。
上圖展示了三級緩存的結構。L1d是一級數據cache,L1i是一級指令cache。請注意,這只是一個示意圖; 現實中的數據流從core到主存的過程中不需要經過任何更高級別的cache。CPU設計人員有很大的自由來設計cache的介面。對於程序員來說,這些設計選擇是不可見的。
另外,我們有擁有多個core的處理器,每個core可以有多個「線程」。核心和線程之間的區別在於,獨立的核心具有所有硬體資源的獨立的副本,早期的多核處理器,甚至具有單獨的第二級緩存而沒有第三級緩存。核心可以完全獨立運行,除非它們在同一時間使用相同的資源,例如與外部的連接。另一方面,線程們共享幾乎所有的處理器資源。英特爾的線程實現只為線程提供單獨的寄存器,甚至是有限的,還有一些寄存器是共享的。
一個現代CPU的完整概貌如圖所示。
由於cache中對應的都是主存地址,即物理地址,在cqu查看具體數據是否在cache中時,如果CPU傳送過來的地址時一個虛擬地址,需要將其轉換成實際物理地址再到cache中去尋找。Cache的實現需要TLB的幫助。可以說TLB命中是Cache命中的基本條件。TLB不命中,會更新TLB項,這個代價非常大,Cache命中的好處基本都沒有了。在TLB命中的情況下,物理地址才能夠被選出,Cache的命中與否才能夠達成。
TLB是一個內存管理單元用於改進虛擬地址到物理地址轉換速度的緩存。TLB是位於內存中的頁表的cache,如果沒有TLB,則每次取數據都需要兩次訪問內存,即查頁表獲得物理地址和取數據。
當cpu對數據進行讀請求時,CPU根據虛擬地址(前20位)到TLB中查找.TLB中保存著虛擬地址(前20位)和頁框號的對映關系,如果匹配到虛擬地址就可以迅速找到頁框號(頁框號可以理解為頁表項),通過頁框號與虛擬地址後12位的偏移組合得到最終的物理地址.
如果沒在TLB中匹配到虛擬地址,就出現TLB丟失,需要到頁表中查詢頁表項,如果不在頁表中,說明要讀取的內容不在內存,需要到磁碟讀取.
TLB是MMU中的一塊高速緩存,也是一種Cache.在分頁機制中,TLB中的數據和頁表的數據關聯,不是由處理器維護,而是由OS來維護,TLB的刷新是通過裝入處理器中的CR3寄存器來完成.如果MMU發現在TLB中沒有命中,它在常規的頁表查找後,用找到的頁表項替換TLB中的一個條目.
當進程進行上下文切換時重新設置cr3寄存器,並且刷新tlb.
有兩種情況可以避免刷tlb.
第一種情況是使用相同頁表的進程切換.
第二種情況是普通進程切換到內核線程.
lazy-tlb(懶惰模式)的技術是為了避免進程切換導致tlb被刷新.
當普通進程切換到內核線程時,系統進入lazy-tlb模式,切到普通進程時退出該模式.
cache是為了解決處理器與慢速DRAM(慢速DRAM即內存)設備之間巨大的速度差異而出現的。cache屬於硬體系統,linux不能管理cache.但會提供flush整個cache的介面.
cache分為一級cache,二級cache,三級cache等等.一級cache與cpu處於同一個指令周期.
CPU從來不從DRAM直接讀/寫位元組或字,從CPU到DRAM的每次讀或寫的第一步都要經過L1 cache,每次以整數行讀或寫到DRAM中.Cache Line是cache與DRAM同步的最小單位.典型的虛擬內存頁面大小為4KB,而典型的Cache line通常的大小為32或64位元組.
CPU 讀/寫內存都要通過Cache,如果數據不在Cache中,需要把數據以Cache Line為單位去填充到Cache,即使是讀/寫一個位元組.CPU 不存在直接讀/寫內存的情況,每次讀/寫內存都要經過Cache.
緩存里有的數據,主存中一定存在。
一級緩存中還分數據緩存(data cache,d-cache)和指令緩存(instruction cache,i-cache)。二者分別用來存放數據和執行這些數據的指令,而且兩者可以同時被cpu訪問,所以一級cache間數據時獨立的。
一級沒有的數據二級可能有也可能沒有。因為一級緩存miss會接著訪問二級緩存。
一級有二級一定有,三級也一定有。因為一級的數據從二級中讀上來的。在一級缺失二級命中時發生。
二級沒有的數據三級可能有也可能沒有。因為二級確實會接著訪問三級緩存。找不到會繼續訪問主存。
二級有的數據三級一定有。在二級缺失三級命中時,數據會從三級緩存提到二級緩存。
三級沒有的數據,主存可能有也可能沒有。三級緩存缺失,會訪問主存,主存也缺失就要從外存訪問數據了。
三級緩存有的數據主存一定有。因為在三級缺失主存命中時,數據會從主存提到三級緩存中來。
一級緩存就是指CPU第一層級的高速緩存,主要是為了緩存指令和緩存數據,一級緩存的容量對CPU性能影響非常大,但是因為成本太高,所以一般容量特別小,也就256KB左右。
二級緩存是CPU第二層級的高速緩存,對於CPU來說,二級緩存容量越大越好,它是直接影響CPU性能的,CPU每個核心都會有自己的緩存,一個CPU的二級緩存容量是所有核心二級緩存容量的總和。
三級緩存就是CPU第三層級的高速緩存,主要是為了降低與內存進行數據傳輸時的延遲問題,三級緩存與一二級不同,三級緩存只有一個,它是所有核心共享,所以在CPU參數中可以看到,三級緩存相對於其他兩級緩存來說都很大。
由於緩存的設置與OS無關且透明,所以對於不同的體系架構下不同的處理器對待緩存區域的處理和方式都不同,不同的處理器也有不同的緩存設置值。從主流的處理器cache大小來看,一般一個cache line的大小都是固定的64B左右,這是經過經驗得到的比較合理的大小,一般一級cache大小在數十KB左右,二級cache大小在數十到數百KB左右,而L3 cache大小在數MB左右。
由於三級cache一般來說是運用於擁有多核的處理器,對於單核處理器來說二級cache就能夠足夠保持夠高的cache命中率。所以一般的三級cache一般只針對於多核處理器。L1和L2級cache是處理器核所單獨的內容。L1又可以看成是L2的cache。L2可以看成是L3級cache的cache。所以我們分兩個部分討論數據放置與數據淘汰策略。
各級cache間的數據放置策略主要有三種。直接相連映射,全相聯映射和組相聯映射。將一個主存塊存儲到唯一的一個Cache行。對應的大小都是一個cache line的大小,一般來說是64B。
多對一的映射關系,但一個主存塊只能拷貝到cache的一個特定行位置上去。cache的行號i和主存的塊號j有如下函數關系:i=j mod m(m為cache中的總行數)。
可以將一個主存塊存儲到任意一個Cache行。
主存的一個塊直接拷貝到cache中的任意一行上
可以將一個主存塊存儲到唯一的一個Cache組中任意一個行。
將cache分成u組,每組v行,主存塊存放到哪個組是固定的,至於存到該組哪一行是靈活的,即有如下函數關系:cache總行數m=u×v 組號q=j mod u
組間採用直接映射,組內為全相聯。硬體較簡單,速度較快,命中率較高。是現代處理器中一般所常用的映射方式。
Cache工作原理要求它盡量保存最新數據,當從主存向Cache傳送一個新塊,而Cache中可用位置已被占滿時,就會產生Cache替換的問題。
常用的替換演算法有下面三種。
LFU(Least Frequently Used,最不經常使用)演算法將一段時間內被訪問次數最少的那個塊替換出去。每塊設置一個計數器,從0開始計數,每訪問一次,被訪塊的計數器就增1。當需要替換時,將計數值最小的塊換出,同時將所有塊的計數器都清零。
這種演算法將計數周期限定在對這些特定塊兩次替換之間的間隔時間內,不能嚴格反映近期訪問情況,新調入的塊很容易被替換出去。
LRU(Least Recently Used,近期最少使用)演算法是把CPU近期最少使用的塊替換出去。這種替換方法需要隨時記錄Cache中各塊的使用情況,以便確定哪個塊是近期最少使用的塊。每塊也設置一個計數器,Cache每命中一次,命中塊計數器清零,其他各塊計數器增1。當需要替換時,將計數值最大的塊換出。
LRU演算法相對合理,但實現起來比較復雜,系統開銷較大。這種演算法保護了剛調入Cache的新數據塊,具有較高的命中率。LRU演算法不能肯定調出去的塊近期不會再被使用,所以這種替換演算法不能算作最合理、最優秀的演算法。但是研究表明,採用這種演算法可使Cache的命中率達到90%左右。
最簡單的替換演算法是隨機替換。隨機替換演算法完全不管Cache的情況,簡單地根據一個隨機數選擇一塊替換出去。隨機替換演算法在硬體上容易實現,且速度也比前兩種演算法快。缺點則是降低了命中率和Cache工作效率。
處理器微架構訪問Cache的方法與訪問主存儲器有類似之處。主存儲器使用地址編碼方式,微架構可以地址定址方式訪問這些存儲器。Cache也使用了類似的地址編碼方式,微架構也是使用這些地址操縱著各級Cache,可以將數據寫入Cache,也可以從Cache中讀出內容。只是這一切微架構針對Cache的操作並不是簡單的地址訪問操作。為簡化起見,我們忽略各類Virtual Cache,討論最基礎的Cache訪問操作,並藉此討論CPU如何使用TLB完成虛實地址轉換,最終完成對Cache的讀寫操作。
Cache的存在使得CPU Core的存儲器讀寫操作略微顯得復雜。CPU Core在進行存儲器方式時,首先使用EPN(Effective Page Number)進行虛實地址轉換,並同時使用CLN(Cache Line Number)查找合適的Cache Block。這兩個步驟可以同時進行。在使用Virtual Cache時,還可以使用虛擬地址對Cache進行定址。為簡化起見,我們並不考慮Virtual Cache的實現細節。
EPN經過轉換後得到VPN,之後在TLB中查找並得到最終的RPN(Real Page Number)。如果期間發生了TLB Miss,將帶來一系列的嚴重的系統懲罰,我們只討論TLB Hit的情況,此時將很快獲得合適的RPN,並依此得到PA(Physical Address)。
在多數處理器微架構中,Cache由多行多列組成,使用CLN進行索引最終可以得到一個完整的Cache Block。但是在這個Cache Block中的數據並不一定是CPU Core所需要的。因此有必要進行一些檢查,將Cache Block中存放的Address與通過虛實地址轉換得到的PA進行地址比較(Compare Address)。如果結果相同而且狀態位匹配,則表明Cache Hit。此時微架構再經過Byte Select and Align部件最終獲得所需要的數據。如果發生Cache Miss,CPU需要使用PA進一步索引主存儲器獲得最終的數據。
由上文的分析,我們可以發現,一個Cache Block由預先存放的地址信息,狀態位和數據單元組成。一個Cache由多個這樣的Cache Block組成,在不同的微架構中,可以使用不同的Cache Block組成結構。我們首先分析單個Cache Block的組成結構。單個Cache Block由Tag欄位,狀態位和數據單元組成,如圖所示。
其中Data欄位存放該Cache Block中的數據,在多數處理器微架構中,其大小為32或者64位元組。Status欄位存放當前Cache Block的狀態,在多數處理器系統中,這個狀態欄位包含MESI,MOESI或者MESIF這些狀態信息,在有些微架構的Cache Block中,還存在一個L位,表示當前Cache Block是否可以鎖定。許多將Cache模擬成SRAM的微架構就是利用了這個L位。有關MOESIFL這些狀態位的說明將在下文中詳細描述。在多核處理器和復雜的Cache Hierarchy環境下,狀態信息遠不止MOESIF。
RAT(Real Address Tag)記錄在該Cache Block中存放的Data欄位與那個地址相關,在RAT中存放的是部分物理地址信息,雖然在一個CPU中物理地址可能有40,46或者48位,但是在Cache中並不需要存放全部地址信息。因為從Cache的角度上看,CPU使用的地址被分解成為了若干段,如圖所示。
這個地址也可以理解為CPU訪問Cache使用的地址,由多個數據段組成。首先需要說明的是Cache Line Index欄位。這一欄位與Cache Line Number類似,CPU使用該欄位從Cache中選擇一個或者一組Entry。
Bank和Byte欄位之和確定了單個Cache的Data欄位長度,通常也將這個長度稱為Cache 行長度,上圖所示的微架構中的Cache Block長度為64位元組。目前多數支持DDR3 SDRAM的微架構使用的Cache Block長度都是64位元組。部分原因是由於DDR3 SDRAM的一次Burst Line為8,一次基本Burst操作訪問的數據大小為64位元組。
在處理器微架構中,將地址為Bank和Byte兩個欄位出於提高Cache Block訪問效率的考慮。Multi-Bank Mechanism是一種常用的提高訪問效率的方法,採用這種機制後,CPU訪問Cache時,只要不是對同一個Bank進行訪問,即可並發執行。Byte欄位決定了Cache的埠位寬,在現代微架構中,訪問Cache的匯流排位寬為64位或者為128位。
剩餘的欄位即為Real Address Tag,這個欄位與單個Cache中的Real Address Tag的欄位長度相同。CPU使用地址中的Real Address Tag欄位與Cache Block的對應欄位和一些狀態位進行聯合比較,判斷其訪問數據是否在Cache中命中
如果cache miss,就去下一級cache或者主存中去查找數據,並將查找到的數據採用上面的數據淘汰策略將數據替換到cache中。
由於在發生cache miss時會產生數據替換,在運行過程中緩存的數據也可能會被修改。所以需要一個策略來保持數據在緩存和主存間的一致性。
Cache寫機制分為write through和write back兩種。
『肆』 緩存一致性協議
鎖緩存行有一套協議叫做 緩存一致性協議 。緩存一致性協議有MSI、MESI、MOSI、Synapse、Firefly以及DragonProtocol等等。
MESI分別代表緩存行數據的4中狀態,通過對這四種狀態的切換,來達到對緩存數據進行管理的目的
假設有三個CPU-A、B、C,對應三個緩存分別是cache-a、b、c。在主內存中定義了x的引用值0
單核讀取
MESI優化和引入的問題:各CPU緩存行的狀態是通過消息傳遞來進行的。如果CPU0要對一個在緩存中共享的變數進行寫入,首先需要發送一個失效的消息給到其他緩存了該數據的CPU,並且要等到他們的確認回執。CPU0在這段時間內都會一直處於阻塞狀態,會導致各種各樣的性能問題和穩定性問題。
為了避免阻塞帶來的資源浪費,在CPU中引入了Store Buffer。
CPU在寫入共享數據時,直接把數據寫入到Store Buffer中,同時發送Invalidate消息,然後繼續去處理其他指令。當收到其他所有CPU發送了Invalidate Acknowledge消息時,再將Store Buffer中的數據存儲到Cache Line中,最後再從Cache Line同步到主內存。
『伍』 EMSI協議
翻譯至 https://en.wikipedia.org/wiki/MESI_protocol
EMSI是基於緩存無效化的一致性緩存協議,並且是一種最常見的支持回寫式緩存的協議。它也被稱為伊利諾伊州協議(由於其在伊利諾伊大學厄本那香檳分校被開發)。回寫式緩存和寫入式緩存相比可以節約很多的帶寬。回寫式緩存經常會存在臟狀態,而臟狀態表明了高數緩存中的數據與主存中的數據不一致。EMSI要求當緩存未命中時並且別的緩存中有該數據,那麼緩存和緩存間應該互相傳輸數據。MESI相對與MSI來說降低了與主存的交互次數,這帶來了顯著的性能提升。
MESI的四個字母分別代表了四個可以被標記在緩存行上的獨立狀態。(也就是用2bit來編碼)
當緩存行處於Modified狀態時,它表明該緩存行只存在於當前緩存中。並且這個緩存行中的數據是臟數據,也就是說這個緩存行中的數據與主存中的數據不一致。緩存被要求在未來將緩存行的數據寫於主存中,但不用立即寫入。但如果別的緩存向該緩存請求這個數據,那必須保證該數據寫入主存已經完成。當回寫回主存完成後,緩存行狀態會有Modified變為Shared狀態。
當緩存行處於Exclusive狀態時,它表明該緩存行只存在於當前緩存中,不過其中的數據與主存中的數據是一致的。當別的緩存向該緩存請求read當前緩存行時,緩存行狀態會變成Shared。或者當有write操作時,他會變成Modified狀態。
當緩存行處於Shared狀態時,它表明該緩存行可能同時存在與別的緩存中,並且其中的數據與主存中一致。這個緩存行隨時可能被丟棄(改變為Invalid狀態)。
當緩存行處於Invalid 狀態時,表明該緩存行是無效的。
對於給定的兩個緩存,以下是允許共同存在的狀態:
當一個緩存中的變數被標記為M狀態,那同樣擁有這個變數的別的緩存的緩存行會被標記為Invalid。
從一個狀態到另一個狀態的轉變有兩個重要影響因素。第一個因素是處理器發出了特殊的讀寫請求。舉個栗子:處理器A的緩存中有變數X,然後這個處理器向自己的緩存發送了對於這個變數的讀寫請求。第二個影響因素是來自別的處理器的請求,這些處理器緩存中沒有這個變數,或者它們想要更新這個變數。這些匯流排請求被一個名叫Snoopers的監聽器監聽著。
下面解釋不同種類的處理器請求和匯流排請求
處理器請求包括如下兩種:
匯流排請求包括如下五種:
如果從主存中獲取一個值需要等待的時間比通過緩存間傳值等待的時間長,那麼我們就可以說緩存間傳值可以降低緩存未命中後的讀延遲。在多核架構下,一致性主要在二級緩存間保持,但處理器仍然有三級緩存,從三級緩存中獲取未命中的變數往往快於從二級緩存。
監控操作 :
所有緩存中的變數都擁有四種狀態的有限狀態機。
對於不同輸入的狀態轉換關系和回復如下表1.1和1.2
只有寫操作發生在Modified或Exclusive狀態的緩存行時,才緩存才不需要做額外操作。如果狀態為Shared的緩存行被寫入,那麼首先別的緩存需要無效它們的緩存行。這個由一個叫 Request For Ownership (RFO) .的廣播操作執行。
當一個變數為Modified時,這個緩存必須監聽所有別的緩存對於該變數對應主存的讀請求,一旦監聽到就必須將這個變數寫入主存。這個過程可以通過強制讓別的緩存等待的方法來完成。當完成了對主存的寫入,狀態變為Shared。但同樣可以直接通知別的緩存這個變數的值,而不寫入主存。
當處於Shared狀態時,必須監聽所有的rfo廣播,一旦收到就讓緩存中的變數無效。
Modified和Exclusive狀態是精確的,當有緩存行處於這個狀態就表明,這個變數是這個緩存獨有的。而Shared狀態時不精確的,當別的緩存丟棄了這個Shared狀態的緩存行,那麼可能只存在一個緩存行狀態為Shared但它不會變為Exclusive。丟棄Shared狀態行不會引起別的緩存的注意。
使用Exclusive可以帶來性能上的提升,因為修改Exclusive不需要通知別的緩存,而修改Shared狀態的緩存行需要告訴別的緩存,並使這些緩存行無效,這是耗時的。(這也是EMSI與MSI協議的區別)
MESI簡單直接的實現存在著兩個性能問題。1.當向一個Invalid的緩存行寫入時,需要從別的緩存獲取值,這是很耗時的。2.需要將別的緩存行的該值設置為Invalid這也是耗時的。為了解決這兩個問題,我們引入了存儲緩沖區和無效化隊列。
當向一個無效的緩存行寫入時會用到儲存緩沖區。因為這個寫操作最終一定會被執行,因此CPU發送讀無效消息(讓別的緩存中的該緩存行無效)並且將要寫入的值放到存儲緩存區中,當這個需要的緩存行寫入緩存時,存儲緩存區中存儲的值將被執行寫入。
存儲緩存區存在帶來的後果是,當一個CPU進行寫操作,值不會立即寫入緩存中。因此,無論何時CPU讀取緩存中的值時,都需要先掃描自己的存儲緩沖區,確保緩沖區中是否還有未寫入的值。值得注意的時不同CPU之間存儲緩沖區時不可見的。
當CPU收到無效請求時,它會將這寫無效請求放入無效化隊列中。放入隊列中的請求會被迅速執行但不是立即執行。所以CPU可以忽略它的緩存塊是無效的。CPU不能掃描它的無效隊列,這是和存儲緩沖區的區別。
可見存儲緩沖區帶來的是寫不同步,而無效化隊列則帶來讀不同步,為了解決這些不同步,我們需要內存屏障。寫屏障會刷新我們的存儲緩沖區,確保裡面所有的寫都會被執行到這個CPU的cache上,而讀屏障可以保證所有無效化隊列里的任務都被執行,確保別的CPU的寫對自己可見。