寫緩衝器 ,無效化佇列 儲存屏障 載入屏障

2022-06-09 12:39:09 字數 1733 閱讀 1823

先來看一下什麼是快取一致性協議

核心思想:如果變數是共享變數,當其他cpu修改這個變數的時候,發出訊號將其他cpu的變數置為失效狀態,其他cpu再使用這一變數的時候會從記憶體中載入這一變數。

修改共享資料的時候,發現相應 快取行的狀態是s, 就是共享,說明其他cpu也有副本, 這時候要發 無效 的通知出去廣播給其他cpu把快取裡面的值為無效(invalid)狀態,然後待收到各個快取的(invalid ack)已經完成無效狀態修改的回應之後,再把自己的狀態改為exclusive,之後再進行修改,修改後再改為modified狀態,資料寫入快取行。

這樣會有乙個缺點,cpu需要在等待所有的invalid ack之後才會進行下面的操作。這會讓cpu產生一定的阻塞,無法充分利用cpu。這個時候就出來了寫緩衝器無效佇列化。

寫緩衝器

寫的時候,發現相應 快取行的狀態是s, 就是共享,說明其他cpu也有副本, 這時候要發 無效 的通知出去廣播給其他cpu把快取裡面的值為無效(invalid)狀態本來是要等回覆才能繼續的, 有了寫緩衝器就可以先把修改的資料放到寫緩衝器,然後通知等其他cpu等他們回覆(ack), 這個時候不會造成執行緒阻塞,cpu可以利用等待的時間繼續向下執行,等回覆都到了以後cpu再來把資料從寫緩衝器搬運到快取行。

儲存**

cpu讀取資料的時候先從寫快取器讀, 沒有 再去 讀快取記憶體, 這樣就可以還是讀到真的資料了

無效化佇列

其他cpu收到無效通知以後, 並不把資料無效化, 而是存入無效化佇列就回覆 收到無效ack,這樣可以讓對方早點收到回覆,等cpu忙完當前的事在進行讀取無效化佇列。

這樣會造成一些問題

儲存**:cpu0 更新了a的值, 寫到寫緩衝器就往下走了,過一陣,要讀a,這時先去寫快取器讀, 讀到的自以為是最新的,但是沒準這一陣時間裡面, cpu1已經改過a的值了,但是, cpu1發過來的無效通知, 是管不到 cpu0的寫緩衝器的。

寫緩衝器:其他cpu還沒有給我們回答的時候我們已經執行下一步**了。

無效化佇列:其他cpu已經給對方應答的時候自己本身還沒有去把這個值改為無效狀態,這樣就造成當前變數已經無效,但是通知還在無效佇列化中,會取到舊值。

儲存屏障 載入屏障

總之, 寫緩衝器 ,無效化佇列 就是導致了可見性問題, 明明寫了 其他執行緒看不到這就需要編譯器等底層系統 借助記憶體屏障

儲存屏障: 讓cpu 將寫緩衝器排空,寫入快取記憶體這叫沖刷, 這樣其他cpu 就會收到通知, 其他cpu可以來拿新資料

載入屏障:cpu 根據無效化佇列裡面的資訊,刪除其快取記憶體的無效資料(就是狀態變為i)

這2個屏障的成對使用, 才能保證更新可見

原文連線:

寫緩衝器與無效化佇列

為什麼需要寫緩衝器和無效化佇列 mesi解決了資料一致性問題,但是效能有了瓶頸,處理器在寫記憶體操作時,必須要等到接收到其他處理器的invalidate acknowledge read response之後才能將資料寫入快取記憶體,為了避免這種情況,設計時引入了寫緩衝器 store buffer ...

緩衝器溢位指南

push ebp 0x8048441 mov esp,ebp 0x8048443 mov 0xc ebp eax 0x8048446 add 0x4,eax 0x8048449 mov eax edx 0x804844b push edx 0x804844c call 0x8048410 0x804...

ByteBuffer 緩衝器(一)

public static void main final string args bytebuffer bytebuffer bytebuffer.allocate 10 system.out.println 初始位置 bytebuffer.position system.out.println ...