mfence, lfence, sfence什麼作用?

mfence, lfence, sfence什麼作用?

// src/backend/utils/rac/lock_free_queu.array_spsc_queue.c
#define mb() 	asm volatile("mfence":::"memory")
#define rmb()	asm volatile("lfence":::"memory")
#define wmb()	asm volatile("sfence" ::: "memory")

就是保證內存訪問的串行化,內部操作就是在一系列內存訪問中添加若干延遲,保證此指令之後的內存訪問發生在此指令之前的內存訪問完成之後(不出現重疊)。
lfence 讀串行化
sfence 寫串行化
mfence 讀寫都串行化

參考

內存屏障

爲什麼需要內存屏障?

由於現代的操作系統都是多處理器.而每一個處理器都有自己的緩存,並且這些緩存並不是實時都與內存發生信息交換.這樣就可能出現一個cpu上的緩存數據與另一個cpu上的緩存數據不一致的問題.而這樣在多線程開發中,就有可能導致出現一些異常行爲. 而操作系統底層爲了這些問題,提供了一些內存屏障用以解決這樣的問題

內存屏障的作用
  1. 阻止屏障兩邊的指令重排序

2. 強制把寫緩衝區/高速緩存中的髒數據等寫回主內存,讓緩存中相應的數據失效(意思就是確保讀到的數據都是內存中的最新的數據,確保數據的有效性)

內存屏障的分類

硬件層提供了一系列的內存屏障 memory barrier / memory fence(Intel的提法)來提供一致性的能力。拿X86平臺來說,有幾種主要的內存屏障

1. lfence,是一種Load Barrier 讀屏障。在讀指令前插入讀屏障,可以讓高速緩存中的數據失效,重新從主內存加載數據

2. sfence, 是一種Store Barrier 寫屏障。在寫指令之後插入寫屏障,能讓寫入緩存的最新數據寫回到主內存

3. mfence, 是一種全能型的屏障,具備ifence和sfence的能力

4. Lock前綴,Lock不是一種內存屏障,但是它能完成類似內存屏障的功能。Lock會對CPU總線和高速緩存加鎖,可以理解爲CPU指令級的一種鎖。它後面可以跟ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG等指令。

Lock前綴實現了類似的能力.

1. 它先對總線/緩存加鎖,然後執行後面的指令,最後釋放鎖後會把高速緩存中的髒數據全部刷新回主內存。

2. 在Lock鎖住總線的時候,其他CPU的讀寫請求都會被阻塞,直到鎖釋放。Lock後的寫操作會讓其他CPU相關的cache line失效,從而從新從內存加載最新的數據。這個是通過緩存一致性協議做的。

內存屏障使用例子

LoadLoad屏障(讀讀屏障):對於這樣的語句Load1; LoadLoad; Load2,在Load2及後續讀取操作要讀取的數據被訪問前,保證Load1要讀取的數據被讀取完畢。
StoreStore屏障(寫寫屏障):對於這樣的語句Store1; StoreStore; Store2,在Store2及後續寫入操作執行前,保證Store1的寫入操作對其它處理器可見。
LoadStore屏障(讀寫屏障):對於這樣的語句Load1; LoadStore; Store2,在Store2及後續寫入操作被刷出前,保證Load1要讀取的數據被讀取完畢。
StoreLoad屏障(寫讀屏障):對於這樣的語句Store1; StoreLoad; Load2,在Load2及後續所有讀取操作執行前,保證Store1的寫入對所有處理器可見。它的開銷是四種屏障中最大的。在大多數處理器的實現中,這個屏障是個萬能屏障,兼具其它三種內存屏障的功能。

java中內存屏障的常見例子

通過 Synchronized關鍵字包住的代碼區域,當線程進入到該區域讀取變量信息時,保證讀到的是最新的值.這是因爲在同步區內對變量的寫入操作,在離開同步區時就將當前線程內的數據刷新到內存中,而對數據的讀取也不能從緩存讀取,只能從內存中讀取,保證了數據的讀有效性.這就是插入了StoreStore屏障
使用了volatile修飾變量,則對變量的寫操作,會插入StoreLoad屏障.
其餘的操作,則需要通過Unsafe這個類來執行.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章