計算機在執行程式時,每條指令都是在cpu中執行的,而執行指令過程中,涉及到資料的讀取和寫入。由於程式執行過程中的臨時資料是存放在sram(物理記憶體)當中的,由於cpu執行速度很快,而從記憶體讀取數 據和向記憶體寫入資料的過程跟cpu執行指令的速度比起來要慢的多,因此如果任何時候對資料的操作都要通過和記憶體的互動來進行,會大大降低指令執行的速度,因此在cpu裡面就有了一級、二級cache(dram)。也就是,當程式在執行過程中,會將運算需要的資料從ram複製乙份到cache中,那麼cpu進行計算時就可以直接從它的cache讀資料和向其寫入資料,當運算結束之後,再將cache中的資料重新整理到物理記憶體當中。對於乙個運算:i++;
當執行緒執行這個語句時,會先從主存當中讀取i的值,然後複製乙份到快取記憶體當中,然後cpu執行指令對i進行加1操作,然後將資料寫入快取記憶體,最後將快取記憶體中i最新的值重新整理到主存當中。這個**在單執行緒中執行是沒有任何問題的,但是在多執行緒中執行就會有問題了。在多核cpu中,每條執行緒可能執行於不同的cpu中,因此每個執行緒 執行時有自己的快取記憶體(對單核cpu來說,其實也會出現這種問題,只不過是以執行緒排程的形式來分別執行的)。比如同時有2個執行緒執行這段**,假如初始時i的值為0,那麼我們希望兩個執行緒執行完之後i的值變為2,但最後的結果有可能是1。
這就是著名的快取一致性問題。通常稱這種被多個執行緒訪問的變數為共享變數。
也就是說,如果乙個變數在多個cpu中都存在快取(一般在多執行緒程式設計時才會出現),那麼就可能存在快取不一致的問題。
為了解決快取不一致性問題,通常來說有以下2種解決方法:
1)通過在匯流排加lock#鎖的方式
2)通過快取一致性協議
這2種方式都是硬體層面上提供的方式。
在早期的cpu當中,是通過在匯流排上加lock#鎖的形式來解決快取不一致的問題。因為cpu和其他部件進行通訊都是通過匯流排來進行的,如果對 匯流排加lock#鎖的話,也就是說阻塞了其他cpu對其他部件訪問(如記憶體),從而使得只能有乙個cpu能使用這個變數的記憶體。比如上面例子中 如果乙個執行緒在執行 i = i +1,如果在執行這段**的過程中,在匯流排上發出了lcok#鎖的訊號,那麼只有等待這段**完全執行完畢之後,其他cpu才能從變數i所在的記憶體讀取變 量,然後進行相應的操作。這樣就解決了快取不一致的問題。
但是上面的方式會有乙個問題,由於在鎖住匯流排期間,其他cpu無法訪問記憶體,導致效率低下。
所以就出現了快取一致性協議。最出名的就是intel 的mesi協議,mesi協議保證了每個快取中使用的共享變數的副本是一致的。它核心的思想是:當cpu寫資料時,如果發現操作的變數是共享變數,即在其 他cpu中也存在該變數的副本,會發出訊號通知其他cpu將該變數的快取行置為無效狀態,因此當其他cpu需要讀取這個變數時,發現自己快取中快取該變數 的快取行是無效的,那麼它就會從記憶體重新讀取。
快取一致性
一般應用而言,追求的都是快取的最終一致性。一般的快取系統,都是按照key去快取查詢,如果不存在對應的value,就應該去後端系統查詢 比如db 如果key對應的value是一定不存在的,並且對該key併發請求量很大,就會對後端系統造成很大的壓力。這就叫做快取穿透。引起這個問題的主要原因還是高併發的時...
快取一致性
計算機體系結構量化研究方法 第五版 學習筆記 快取一致性 1 快取一致性的問題 2 儲存器一致性的概念 3 一致性的基本實現方案 大型 多級快取可以充分降低處理器對儲存頻寬的需求。採用對稱共享儲存器的計算機通常支援對共享資料與專用資料的快取。多處理器之間的通訊基本上是通過讀寫共享資料實現。為了降低訪...
Linux記憶體管理 DMA和一致性快取
cpu寫記憶體的時候有兩種方式 1.write through cpu直接寫記憶體,不經過cache。2.write back cpu只寫到cache中。cache的硬體使用lru演算法將cache裡面的內容替換到記憶體。通常是這種方式。dma可以完成從記憶體到外設直接進行資料搬移。但dma不能訪問...