1.1、計算機硬體記憶體架構。
計算機cpu(central processing unit)和記憶體的互動是最頻繁的,記憶體是我們的快取記憶體區。使用者磁碟和cpu的互動,而cpu運轉速度越來越快,磁碟遠遠跟不上cpu的讀寫速度,才設計了記憶體,使用者快取使用者io等待導致cpu的等待成本。但是隨著cpu的發展,記憶體的讀寫速度也遠遠跟不上cpu的讀寫速度,因此,為了解決這一糾紛,cpu廠商在每顆cpu上加入了快取記憶體,用來緩解這種症狀,cpu與記憶體的互動如下圖:
速快取讀取資料和向其中寫入資料,當運算結束之後,再將快取記憶體中的資料重新整理到主存當中。
同樣,我們知道單核cpu的主頻不可能無限增長,想要提公升效能,需要多個處理器協同工作,intel總裁貝瑞特單膝下跪事件標識著多核時代的到來。
基於快取記憶體的儲存互動很好的解決了處理器與記憶體之間的矛盾,也引入了新的問題:快取一致性問題。
在多處理器系統中,每個處理器有自己的快取記憶體,而他們又共享同一塊記憶體(主存),當多個處理器運算都涉及到同一塊記憶體區域的時候,就有可能出現快取不一致的問題
,比如下面這段**:
i=i+1;
當執行緒執行這個語句時,會先從主存當中讀取i的值,然後複製乙份到快取記憶體當中,然後cpu執行指令對i進行加1操作,然後將資料寫入快取記憶體,最後將快取記憶體中i最新的值重新整理到主存當中。
這個**在單執行緒中執行是沒有任何問題的,但是在多執行緒中執行就會有問題了。在多核cpu中,每條執行緒可能執行於不同的cpu中,因此每個執行緒執行時有自己的快取記憶體(對單核cpu來說,其實也會出現這種問題,只不過是以執行緒排程的形式來分別執行的)。本文我們以多核cpu為例。
假設同時有2個執行緒執行這段**,假如初始時i的值為0,那麼我們希望兩個執行緒執行完之後i的值變為2,但是事實會是這樣嗎?
可能存在下面一種情況:初始時,兩個執行緒分別讀取i的值存入各自所在的cpu的快取記憶體當中,然後執行緒1進行加1操作,然後把i的最新值1寫入到記憶體。此時執行緒2的快取記憶體當中i的值還是0,進行加1操作之後,i的值為1,然後執行緒2把i的值寫入記憶體。
最終結果i的值是1,而不是2,這就是快取一致性問題。通常稱這種被多個執行緒訪問的變數為共享變數。也就是說,如果乙個變數在多個cpu中都存在快取(一般在多執行緒程式設計時才會出現),那麼就可能存在快取不一致的問題。
為了解決這一問題,在硬體層面的解決辦法有兩種:
( 1 )通過在匯流排加lock#鎖的方式。
在早期的cpu當中,是通過在匯流排上加lock#鎖的形式來解決快取不一致的問題。因為cpu和其他部件進行通訊都是通過匯流排來進行的,如果對匯流排加lock#鎖的話,也就是說阻塞了其他cpu對其他部件訪問(如記憶體),從而使得只能有乙個cpu能使用這個變數的記憶體。
但是這種方式會有乙個問題,由於在鎖住匯流排期間,其他cpu無法訪問記憶體,導致效率低下。
( 2 )通過快取一致性協議。
需要各個處理器執行時都遵守一些協議,在執行時將需要這些協議儲存資料的一致性。協議包括:msi/mesi/mosi/synapse/firely/dragonprotocol等。
最出名的就是intel的mesi協議,mesi協議保證了每個快取中使用的共享變數的副本是一致的。它核心的思想是:當cpu寫資料時,如果發現操作的變數是共享變數,即在其他cpu中也存在該變數的副本,會發出訊號通知其他cpu將該變數的快取行置為無效狀態,因此當其他cpu需要讀取這個變數時,發現自己快取中快取該變數的快取行是無效的,那麼它就會從記憶體重新讀取。
計算機記憶體定址
摘自 1 基本概念 cpu段式管理 段式管理的基本原理是指把乙個程式分成若干個段 segment 進行儲存,每個段都是乙個邏輯實體 logical entity 乙個使用者作業或程序所包含的段對應乙個二維線形虛擬空間,程式通過分段 segmentation 劃分為多個模組,故可以對程式的各個模組分別...
計算機記憶體管理
在計算機中,儲存區域主要分為 他們的執行速率自下而上加快,與之相應的造價越高。其中,硬碟的執行效率最慢,暫存器的效率最快。在c 中,記憶體主要分為五個區,分別是 區是用來儲存程式的所有 以及字串常量等在編譯期間就能確定的值,在程式的整個生命週期內,在常量資料區的資料都是可用的。在這個區域內,所有的資...
計算機記憶體分配 管理
當我們寫完乙個程式後,編譯 鏈結 執行,表面看似很簡單,其實程式執行過程中,記憶體為我們的程式做了很多事。我們先來看乙個圖 一般我們將記憶體分為 堆區 棧區 全域性區 區 常量區,各個區域存放的內容 棧區 在程式中所建立的區域性變數 引數 陣列 指標等,當程式執行完後,將釋放所占用的該塊記憶體。堆區...