① 如果,有invalidatequeue 組件的話比較明顯的是會出現loadload重排序重排序,因為后面的load可能拿到的坑是舊值,斷言失敗](https://zhuanlan.zhihu.com/p/125549632)
② 如果,有invalidatequeue 組件的話,在NUCA下,因為cpu可能會划分為多個cache組,我認為會出現 load store 重排序,另一組cpu會認為 c = 1和while發生了重排
③ 在 x86下,基於 FIFO 的storebuffer 可以保證storestore的順序性
首先x86無 invalidatequeue, 可以保證無 loadload 和 load store排序,基於 FIFO 的storebuffer,且x86 的架構,強制 CPU 必須先寫入 StoreBuffer,再寫入 cache 可以保證storestore的順序性
https://xie.infoq.cn/article/680fd531df57856ddcb532914
CPU在cache line狀態的轉化期間是阻塞的,經過長時間的優化,在寄存器和L1緩存之間添加了LoadBuffer、StoreBuffer來降低阻塞時間,LoadBuffer、StoreBuffer,合稱排序緩沖(Memoryordering Buffers (MOB)),Load緩沖64長度,store緩沖36長度,Buffer與L1進行數據傳輸時,CPU無須等待。
CPU執行load讀數據時,把讀請求放到LoadBuffer,這樣就不用等待其它CPU響應,先進行下面操作,稍后再處理這個讀請求的結果。
CPU執行store寫數據時,把數據寫到StoreBuffer中,待到某個適合的時間點,把StoreBuffer的數據刷到主存中。
http://web.cecs.pdx.edu/~alaa/ece587/notes/memory-ordering.pdf
http://yizhanggou.top/volatile/
https://github.com/luohaha/MyBlog/issues/4
https://stackoverflow.com/questions/11105827/what-is-a-store-buffer
================ 在intel手冊中關於重排序的描述 =========================
1、Reads are not reordered with other reads.
不需要特殊fence指令就能保證LoadLoad
2.Writes are not reordered with older reads.
不需要特殊fence指令就能保證LoadStore
3.Writes to memory are not reordered with other writes.
不需要特殊fence指令就能保證StoreStore
4.Reads may be reordered with older writes to different locations but not with older writes to the same location.
需要特殊fence指令才能保證StoreLoad, 有名的Peterson algorithm算法就是需要StoreLoad的典型場景
需要注意的是,前三點並沒有強調 different locations
or same location
情況,最后一點卻強調了,read-read 和write-write 之間,不管是否同地址不能重排,且前面的read不能和write重排
https://www.intel.co.kr/content/www/kr/ko/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html
================ 在某博客中關於重排序的描述 =========================
為什么這一堆 Barrier 里 StoreLoad 最重?
所謂的重實際就是跟內存交互次數,交互越多延遲越大,也就是越重。StoreStore, LoadLoad 兩個都不提了,因為它倆要么只限制讀,要么只限制寫,也即只有一次內存交互。只有 LoadStore 和 StoreLoad 看上去有可能對讀寫都有限制。但 LoadStore 里實際限制的更多的是讀,即 Load 數據進來,它並不對最后的 Store 存出去數據的可見性有要求,只是說 Store 不能重排到 Load 之前。而反觀 StoreLoad,它是說不能讓 Load 重排到 Store 之前,這么一來得要求在 Load 操作前刷寫 Store Buffer 到內存。不去刷 Store Buffer 的話,就可能導致先執行了讀取操作,之后再刷 Store Buffer 導致寫操作實際被重排到了讀之后。而數據一旦刷寫出去,別的 CPU 就能看到,看到之后可能就會修改下一步 Load 操作的內存導致 Load 操作的內存所在 Cache Line 無效。如果允許 Load 操作從一個可能被 Invalidate 的 Cache Line 里讀數據,則表示 Load 從實際意義上來說被重排到了 Store 之前,因為這個數據可能是 Store 前就在 Cache 中的,相當於讀操作提前了。為了避免這種事發生,Store 完成后一定要去處理 Invalidate Queue,去判斷自己 Load 操作的內存所在 Cache Line 是否被設置為無效。這么一來為了滿足 StoreLoad 的要求,一方面要刷 Store Buffer,一方面要處理 Invalidate Queue,則最差情況下會有兩次內存操作,讀寫分別一次,所以它最重。
StoreLoad 為什么能實現其它 Barrier 的功能?
這個也是從前一個問題結果能看出來的。StoreLoad 因為對讀寫操作均有要求,所以它能實現其它 Barrier 的功能。其它 Barrier 都是只對讀寫之中的一個方面有要求。
不過這四個 Barrier 只是 Java 為了跨平台而設計出來的,實際上根據 CPU 的不同,對應 CPU 平台上的 JVM 可能可以優化掉一些 Barrier。比如很多 CPU 在讀寫同一個變量的時候能保證它連續操作的順序性,那就不用加 Barrier 了。比如 Load x; Load x.field 讀 x 再讀 x 下面某個 field,如果訪問同一個內存 CPU 能保證順序性,兩次讀取之間的 Barrier 就不再需要了,根據字節碼編譯得到的匯編指令中,本來應該插入 Barrier 的地方會被替換為 nop,即空操作。在 x86 上,實際只有 StoreLoad 這一個 Barrier 是有效的,x86 上沒有 Invalidate Queue,每次 Store 數據又都會去 Store Buffer 排隊,所以 StoreStore, LoadLoad 都不需要。x86 又能保證 Store 操作都會走 Store Buffer 異步刷寫,Store 不會被重排到 Load 之前,LoadStore 也是不需要的。只剩下一個 StoreLoad Barrier 在 x86 平台的 JVM 上被使用。
https://juejin.cn/post/6844904144273145863
由於 x86 是遵循 TSO 的最終一致性模型,如若出現 data race 的情況還是需要考慮同步的問題,尤其是在 StoreLoad 的場景。而其余場景由於其 store buffer 的特殊性以及不存在 invalidate queue 的因素,可以不需要考慮重排序的問題,因此在 x86 平台下,除了 StoreLoad Barrier 以外,其余的 Barrier 均為空操作。
https://www.zhihu.com/question/274310265/answer/1271612645
https://zhuanlan.zhihu.com/p/81555436
================ 在jdk官方文檔的描述 =========================
Total Store Order (TSO) machines can be seen as machines issuing a release store for each store and a load acquire for each load.
Therefore there is an inherent resemblence between TSO and acquire/release semantics.
TSO can be seen as an abstract machine where loads are executed immediately when encountered (hence loadload reordering not happening) but enqueues stores in a FIFO queue for asynchronous serialization (neither storestore or loadstore reordering happening).
The only reordering happening is storeload due to the queue asynchronously serializing stores (yet in order).
http://hg.openjdk.java.net/jdk10/jdk10/hotspot/file/5ab7a67bc155/src/share/vm/runtime/orderAccess.hpp
================ FQA =========================
因此,MESI協議最多只是保證了對於一個變量,在多個核上的讀寫順序,對於多個變量而言是沒有任何保證的。很遺憾,還是需要volatile~~
答案仍然是需要的。因為 MESI只是保證了多核cpu的獨占cache之間的一致性,但是cpu的並不是直接把數據寫入L1 cache的,中間還可能有store buffer。有些arm和power架構的cpu還可能有load buffer或者invalid queue等等。因此,有MESI協議遠遠不夠。
https://blog.csdn.net/org_hjh/article/details/109626607