Loading AI tools
来自维基百科,自由的百科全书
主記憶體屏障(英語:Memory barrier),也稱主記憶體柵欄,主記憶體柵障,屏障指令等,是一類同步屏障指令,它使得 CPU 或編譯器在對主記憶體進行操作的時候, 嚴格按照一定的順序來執行, 也就是說在主記憶體屏障之前的指令和之後的指令不會由於系統最佳化等原因而導致亂序。
大多數現代電腦為了提高效能而採取亂序執行,這使得主記憶體屏障成為必須。
語意上,主記憶體屏障之前的所有寫操作都要寫入主記憶體;主記憶體屏障之後的讀操作都可以獲得同步屏障之前的寫操作的結果。因此,對於敏感的程式塊,寫操作之後、讀操作之前可以插入主記憶體屏障。
當驅動程式執行下列動作時,如果處理器的寫入指令 out-of-order,使得資料還沒有寫入記憶體,硬體模組就被觸發開始動作,就會產生錯誤的行為。
寫資料到記憶體, 稍後硬體模塊會存取這一筆資料
// 此處需要內存屏障
觸發硬體模塊開始處理資料
大多數處理器提供了主記憶體屏障指令:
主記憶體屏障是底層原語,是主記憶體排序的一部分,在不同體系結構下變化很大而不適合推廣。需要認真研讀硬體的手冊以確定主記憶體屏障的辦法。x86指令集中的主記憶體屏障指令是:
lfence (asm), void _mm_lfence (void) 读操作屏障 sfence (asm), void _mm_sfence (void)[1] 写操作屏障 mfence (asm), void _mm_mfence (void)[2] 读写操作屏障
常見的x86/x64,通常使用lock指令字首加上一個空操作來實現,注意當然不能真的是nop指令,但是可以用來實現空操作的指令其實是很多的,比如Linux中採用的
addl $0, 0 (%esp)
記憶體也提供了另一套語意[3]的主記憶體屏障指令:
Intel Itanium處理器,具有主記憶體屏障mf的指令,具有下述modifiers:
下述同步函式使用適當的屏障來確保主記憶體有序:
多執行緒程式通常使用高層程式設計語言中的同步原語,如Java與.NET Framework,或者API如pthread或Windows API。因此一般不需要明確使用主記憶體屏障。
主記憶體可見性問題,主要是高速緩衝記憶體與主記憶體的一致性問題。一個處理器上的執行緒修改了某資料,而在另一處理器上的執行緒可能仍然使用著該資料在專用cache中的老值,這就是可見性出了問題。解決辦法是令該資料為volatile屬性,或者讀該資料之前執行主記憶體屏障。
C與C++語言中,volatile關鍵字意圖允許主記憶體對映的I/O操作。這要求編譯器對此的資料讀寫按照程式中的先後順序執行,不能對volatile主記憶體的讀寫重排序。因此關鍵字volatile並不保證是一個主記憶體屏障。[4]
對於Visual Studio 2003,編譯器保證對volatile的操作是有序的,但是不能保證處理器的亂序執行。因此,可以使用InterlockedCompareExchange或InterlockedExchange函式。
對於Visual Studio 2005及以後版本,編譯器對volatile變數的讀操作使用acquire semantics,對寫操作使用release semantics。
編譯器會對生成的可執行代碼做一定最佳化,造成亂序執行甚至省略(不執行)。gcc編譯器在遇到內嵌組譯語句:
asm volatile("" ::: "memory");
將以此作為一條主記憶體屏障,重排序主記憶體操作。即此語句之前的各種編譯最佳化將不會持續到此語句之後。也可用內建的__sync_synchronize
Microsoft Visual C++的編譯器主記憶體屏障為:
_ReadWriteBarrier() MemoryBarrier()
Intel C++編譯器的主記憶體屏障為:
__memory_barrier()
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.