2013-08-26 31 views
32

一個編譯圍欄的概念經常出現,當我讀到內存模型,障礙,訂貨,原子能等,但通常是在上下文有CPU圍欄配對,如人們所期望的那樣。何時編譯器內存屏障(如std :: atomic_signal_fence)有用?

然而,偶爾我會看到圍欄結構只有適用於編譯器。這方面的一個例子是C++ 11 std::atomic_signal_fence功能,其在cppreference.com規定:

的std :: atomic_signal_fence相當於標準:: atomic_thread_fence,除了沒有對CPU存儲器排序 指令被髮布。按照順序指示,僅編譯器重新排序 指令。

我有關於這個主題的五個問題:

  1. 正如顧名思義std::atomic_signal_fence,是一個異步中斷(如內核被搶佔一個線程來執行信號處理程序)只有其中編譯器只有柵欄是有用的情況下?

  2. 它的用處適用於所有架構,包括強烈訂購例如x86

  3. 能否在具體例如提供展示一個編譯器只圍欄的用處?

  4. 使用std::atomic_signal_fence時,使用acq_relseq_cst排序是否有區別? (我希望它沒有什麼區別。)

  5. 這個問題可能是由第一個問題所覆蓋,但我足夠的好奇,一下也無妨明確要求:它是有史以來必要用圍欄與thread_local訪問? (如果它曾經是,我希望只編譯圍欄如atomic_signal_fence是首選的工具。)

謝謝。

+2

你檢查了嗎? http://preshing.com/20120625/memory-ordering-at-compile-time。 –

+1

引用preshing.com:「正如我所提到的,**編譯器的屏障足以防止單處理器系統上的內存重新排序**,但現在是2012年,而現在多核計算已成爲常態,如果我們要確保我們的[...]「 –

+1

@chico:好的一點 - 如果程序員**知道**應用程序將會*在一個多處理器環境中按照期望的順序進行交互, * only **在非SMP系統上運行(即由於某種原因,單核CPU **或** SMP在內核中被禁用),這是編譯器不可能知道或假設的,然後是'atomic_signal_fence' (或其他*僅限編譯器* fence構造)可用作潛在的優化。正如文章所述,Linux內核具有以這種方式實現的函數「smp_rmb」和「smp_wmb」。但是,我仍然有興趣聽到答案 - 如果存在的話 - 不限於這種假設。 – etherice

回答

21

爲了回答所有5個問題:


1)編譯器圍欄(由本身不帶一個CPU圍欄)僅在情況下有用:

  • 要強制執行內存順序約束單線程與異步中斷處理程序 bou找到相同的線程(例如信號處理程序)。

  • 要強制存儲器順序約束多個線程之間時,它保證了每個線程將執行在相同的CPU核心。換句話說,應用程序只能在single core系統上運行,或者應用程序採取特殊措施(通過processor affinity)確保共享數據的每個線程都綁定到相同的核心。


2)基礎體系結構的存儲器模型,不管是strongly-或弱有序,對是否需要在的情況的編譯器圍欄沒有軸承。


3)在此是僞代碼這證明了使用一個編譯器圍欄的,其本身充分地同步的螺紋和結合到相同的線程異步信號處理程序之間的存儲器存取:

void async_signal_handler() 
{ 
    if (is_shared_data_initialized) 
    { 
     compiler_only_memory_barrier(memory_order::acquire); 
     ... use shared_data ... 
    } 
} 

void main() 
{ 
// initialize shared_data ... 
    shared_data->foo = ... 
    shared_data->bar = ... 
    shared_data->baz = ... 
// shared_data is now fully initialized and ready to use 
    compiler_only_memory_barrier(memory_order::release); 
    is_shared_data_initialized = true; 
} 

重要提示:本示例假定async_signal_handler綁定到初始化shared_data並設置is_initialized標誌相同的線程,這意味着應用程序是單線程的,或將其設置threa d信號相應地屏蔽。否則,編譯器圍欄將不足,並且CPU圍欄也將需要。


4)它們應該是相同的。acq_relseq_cst都應該產生一個完整的(雙向)編譯器圍欄,並且不會發出與圍欄相關的CPU指令。 「順序一致性」的概念僅在涉及多個內核和線程時才起作用,並且atomic_signal_fence僅適用於一個執行線程。


5)號公報(當然,除非線程本地數據從在這種情況下,編譯器圍欄可能是必要的異步信號處理程序訪問的)。否則,不應該需要具有螺紋柵欄 - 本地數據,因爲編譯器(和CPU)只允許以不改變程序相對於其sequence points從單線程角度來看可觀察行爲的方式對存儲器訪問進行重新排序。在邏輯上,我們可以將多線程程序中的線程局部靜態數據視爲與單線程程序中的全局靜態數據相同。在這兩種情況下,數據只能從單個線程訪問,這可以防止發生數據競爭。

+0

非常明確,內容翔實。 +1。 – etherice

+1

內容翔實,但不準確。還有其他一些情況,其中只有編譯器的柵欄在特定處理器的C11之前的代碼中很有用。例如,如果您在x86上,並且對獲取釋放感到滿意,但希望允許編譯器將內存操作重新排序到塊中的不同地址,則圍繞該塊的編譯器(但保留內存訪問非易失性)是唯一的實現這一目標的方法。 – user2949652

2

實際上有一些不可移植但有用的C編程習慣用法,即使在多核代碼中(特別是在C11之前的代碼中)編譯器柵格也是有用的。典型的情況是程序正在進行一些通常會變得不穩定的訪問(因爲它們是共享變量),但是您希望編譯器能夠移動訪問。如果您知道目標平臺上的訪問是原子級的(並且您採取了其他預防措施),則可以將訪問保留爲非易失性,但包含使用編譯器屏障的代碼移動。謝謝,這樣的大多數編程已經被C11/C++ 11輕鬆原子作廢了。

相關問題