多線程編程,CPU是如果解決多線程內存訪問問題的
CPU對內存變量的修改是先讀取內存數據到CPU Cache中,然後再由CPU做運算,運算完成後繼續寫入到內存中
在單核CPU中,這完全沒有問題,然而在多核CPU中,每一個CPU核心都擁有自己獨立的Cache
此時同時訪問同一個內存地址時,將會把內存值復制到多個CPU的Cache中
此時如果對Cache中的值進行修改數據就將會不一致,寫入到內存時,內存中的數據就將會達不到預期值
為了解決這一個問題,早期CPU中,采用了總線LOCK的辦法,某個CPU要對內存操作的時候,總線進行LOCK,直到操作完成再UNLOCK
總線包含了許多設備的控制,LOCK將會大大降低資源處理的速度,於是intel提出了MESI協議
intel自從奔騰之後就開始引入MESI協議,目前許多CPU都在使用該協議的變種
MESI中,一個Cache被稱為Row,不同CPU Cache中同一個內存地址的副本,他們的row都是相同的
Row有4種狀態,他們分別是
狀態 |
描述 |
M(Modified) |
這行數據有效,數據被修改了,和內存中的數據不一致,數據只存在於本Cache中。 |
E(Exclusive) |
這行數據有效,數據和內存中的數據一致,數據只存在於本Cache中。 |
S(Shared) |
這行數據有效,數據和內存中的數據一致,數據存在於很多Cache中。 |
I(Invalid) |
這行數據無效。 |
Exclusive獨占
M修改狀態
每個CPU在讀寫自己的Cache row的同時,也會監聽其他CPU的Cache row
當只有一個CPU擁有內存副本時,設置為E(Exclusive)狀態
當第二個CPU讀取內存副本時,設置為S(Shared)狀態
當其他CPU修改內存副本時,設置為I(Invalid)狀態
當前CPU修改內存副本時,設置為M(Modified)狀態
每個CPU Cache row都有自己的一個狀態
MESI狀態之間的遷移過程如下:
當前狀態 |
事件 |
行為 |
下一個狀態 |
I(Invalid) |
Local Read |
如果其它Cache沒有這份數據,本Cache從內存中取數據,Cache line狀態變成E; 如果其它Cache有這份數據,且狀態為M,則將數據更新到內存,本Cache再從內存中取數據,2個Cache 的Cache line狀態都變成S; 如果其它Cache有這份數據,且狀態為S或者E,本Cache從內存中取數據,這些Cache 的Cache line狀態都變成S |
E/S |
Local Write |
從內存中取數據,在Cache中修改,狀態變成M; 如果其它Cache有這份數據,且狀態為M,則要先將數據更新到內存; 如果其它Cache有這份數據,則其它Cache的Cache line狀態變成I |
M |
|
Remote Read |
既然是Invalid,別的核的操作與它無關 |
I |
|
Remote Write |
既然是Invalid,別的核的操作與它無關 |
I |
|
E(Exclusive) |
Local Read |
從Cache中取數據,狀態不變 |
E |
Local Write |
修改Cache中的數據,狀態變成M |
M |
|
Remote Read |
數據和其它核共用,狀態變成了S |
S |
|
Remote Write |
數據被修改,本Cache line不能再使用,狀態變成I |
I |
|
S(Shared) |
Local Read |
從Cache中取數據,狀態不變 |
S |
Local Write |
修改Cache中的數據,狀態變成M, 其它核共享的Cache line狀態變成I |
M |
|
Remote Read |
狀態不變 |
S |
|
Remote Write |
數據被修改,本Cache line不能再使用,狀態變成I |
I |
|
M(Modified) |
Local Read |
從Cache中取數據,狀態不變 |
M |
Local Write |
修改Cache中的數據,狀態不變 |
M |
|
Remote Read |
這行數據被寫到內存中,使其它核能使用到最新的數據,狀態變成S |
S |
|
Remote Write |
這行數據被寫到內存中,使其它核能使用到最新的數據,由於其它核會修改這行數據, 狀態變成I |
I |
多線程編程,CPU是如果解決多線程內存訪問問題的