volatile為什么可以保證內存可見性及防止指令重排序?


內存

共享主存和高速緩存(工作內存)。CPU高速緩存(L1,2)產生原因讀寫主存沒有CPU執行指令快,他是某個CPU獨有,只與該CPU運行的線程有關。

內存可見性

簡單的說,CPU對數據的修改,對其他CPU立刻可見。下面我們詳細地說。

  1. CPU修改數據,首先對工作內存修改,再同步主內存。單線程中,變量在工作內存的副本一直有效,CPU不用每次修改從主存讀取變量,只是每次修改后同步主存。
  2. 對其他CPU立刻可見。當一個CPU修改變量,同步主存,如果其他CPU的工作內存也緩存這個變量,那么這個CPU的變量失效,當這個CPU想修改變量,必須從主存重新獲取變量。

volatile保證內存可見性基於MESI協議實現的。MESI協議是緩存一致性協議一種。

題外話,如何保持CPU緩存一致性

第一種,操作系統在總線上發出lock信號,其他處理器既不能操作緩存了該共享變量內存地址的緩存,阻塞其他CPU,使該處理器可以獨享此共享內存。總線鎖定把CPU和內存的通信鎖住,使得其他處理器在鎖定期間不能操作其他內存地址的數據。

第二種,緩存一致性機制。當對某塊CPU對緩存的數據操作后,通知其他CPU廢棄存儲在內部的緩存,或者從主存重新讀取。

MESI協議

M:Modify,數據只在本CPU緩存,其他CPU沒有,且數據修改沒有更新到內存

E:Exclusive, 獨占。數據只在本CPU中緩存,且沒有修改,即與內存中一致

S:Shared,數據在多個CPU都有緩存,且與內存一致

I:Invalid,本CPU中的這份緩存無效

該協議要求每個緩存行維護上面4個狀態中的2個狀態。CPU修改數據,這個CPU的數據狀態更新M,其他CPU的數據狀態更新I。

重排序

保證緩存一致性,所以在CPU的L1緩存設置store buffer\ load buffer。導致CPU執行順序和程序不一致。

Memory Barrier

1.分割代碼,阻止柵欄前后沒有數據依賴性的代碼進行指令重排序,保證程序一定程度有序

2.強制把store buffer/高速緩存的臟數據寫回主存,緩存中相應數據失效,保證內存可見性

StoreLoad Barrier保證barrier前所有內存訪問指令完成后,才執行barrier后內存訪問指令

happens-before原則(重排序准則)

1. 程序次序規則:一個線程內,按照代碼順序,書寫在前面的操作先行發生於書寫在后面的操作;
2. 鎖定規則:一個unLock操作先行發生於后面對同一個鎖額lock操作;
3. volatile變量規則:對一個變量的寫操作先行發生於后面對這個變量的讀操作;
4. 傳遞規則:如果操作A先行發生於操作B,而操作B又先行發生於操作C,則可以得出操作A先行發生於操作C;
5. 線程啟動規則:Thread對象的start()方法先行發生於此線程的每個一個動作;
6. 線程中斷規則:對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生;
7. 線程終結規則:線程中所有的操作都先行發生於線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到線程已經終止執行; 對象終

volatile

采用memory barrier實現,保證可見性,禁止指令重排序,不保證原子操作。

每個volatile寫操作的前后插入一個StoreStore屏障
每個volatile讀操作的前后面插入一個LoadLoad屏障

可看,https://blog.csdn.net/ysq222/article/details/88771218


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM