什么是內存一致性模型
內存一致性模型決定了不同的線程對共享內存的訪問的可見性,也就是說,當不同的線程寫同一塊內存時, 讀內存會返回什么值.
考慮下面的例子:
初始狀態: x = y = 0;
Processor 0:
(1) x = 1;
(2) print (y);
Processor 1:
(3) y = 1;
(4) print(x);
假設在如下的CPU架構上執行,並且硬件上保證了cache一致性.
那么上述代碼最終會打印出什么值呢?
這依賴於所用的內存一致性模型
順序一致性模型SC (Sequential Consistency)
CPU嚴格按照程序中的順序執行,上述例子有如下幾種執行順序:
(1)->(2)->(3)->(4): 輸出 0 1;
(3)->(4)->(1)->(2): 輸出 0 1;
(1)->(3)->(2)->(4): 輸出 1 1;
(1)->(3)->(4)->(2): 輸出 1 1;
....
等等, 最終結果可以是 0 1或者 1 1, 但不能為 0 0
在順序一致性模型里, 在前一條指令完成前, 不會執行后一條指令, (1)是一條寫操作,由於緩存架構(L1/L2/L3),速度是相當於的慢.
寬松內存模型(Relaxed memory models)
對於(2)而言,為什么一定要等(1)執行完才能執行呢?它們並沒有什么直接的聯系, 因此在硬件上設計了一個store buffer, 如下圖:
(1)執行時直接寫入store buffer后, (2)就可以緊接着可以執行,如果store buffer以FIFO的方式運行, 這種模型稱為total store ordering (TSO)
Total store ordering (TSO)
回到前面的例子,
(1)和(3)已經執行完, 將值寫入到store buffer, 緊接着(2)和(4)執行, 這時(2)執行, 它首先到store buffer中查找是否有B的值, 但發現沒有, 所以從內存中讀取B的值,得到0, 同樣(4)也有可能會獲取到0, 這樣程序的輸出結果就是 0 0, 這在SC模型中是不可能的值.
Partial Consistency Ordering(PSO)
TSO保證CPU以FIFO的方式來處理store buffer, 但如果store buffer中的指令涉及不同的地址,允許CPU重排它們的順序以便獲得性能的提升,這就是
Partial Consistency Ordering, PSO僅保證地址相關指令在順序.
內存屏障
在寬松內存一致性模型下, 程序可能出現與預期不一致的結果, 比如例子中輸出 0 0,因此芯片設計廠商提供了同步指令用來控制指令的運行順序,常用的指令為內存屏障barrier(or fence), 內存屏障強制保證在它之前的所有的內存操作指令必須完成后才能執行之后的指令.也就是內存屏障指令保證了該點的順序一致性.
通常內存屏障指令分為讀內存屏障,寫內存屏障和讀寫內存屏障, 例如arm中:
- LD load-load/load-store
- ST store-store/store-load
- SY any-any
編譯亂序
前面的亂序行為我們稱為執行亂序, 事實上編譯器也會進行指令重排從而導致亂序.編譯器可以對訪存的指令進行亂序,減少邏輯上不必要的訪存,以及盡量提高 Cache 命中率和 CPU 的 Load/Store 單元的工作效率。因此在打開編譯器優化以后,有時會看到生成的匯編碼並沒有嚴格按照代碼的邏輯順序。因此同樣需要內存屏障指令以保證程序執行的正確性.