#include <atomic>
std::atomic<int> val{1};
const auto my_order = std::memory_order_relaxed; // const lvalue
int main()
{
val.store(42, my_order);
}
此代碼沒有相關性,但我注意到有關內存排序的奇怪事情。編譯器產生以下組件爲主要(x86_64的,克++ 6.2.1,與-O3編譯):當非const值左值時,memory_order更改爲默認值
0x00000000004004c0 <+0>: movl $0x2a,0x200b5a(%rip) # 0x601024 <val>
0x00000000004004ca <+10>: xor %eax,%eax
0x00000000004004cc <+12>: retq
沒有特殊的CPU指令處理原子預計在x86與std::memory_order_relaxed
排序。
然而,當const
限定符從my_order
auto my_order = std::memory_order_relaxed; // non-const lvalue
除去編譯器生成的組裝變得:
0x00000000004004c0 <+0>: movl $0x2a,0x200b5a(%rip) # 0x601024 <val>
0x00000000004004ca <+10>: xor %eax,%eax
0x00000000004004cc <+12>: mfence
0x00000000004004cf <+15>: retq
的mfence
指令似乎表明std::memory_order_seq_cst
排序現在使用(缺省值)。這對我來說有點令人驚訝。即使my_order
是一個左值(非常規來指定內存排序),它是通過值傳遞(仍std::memory_order_relaxed
),我看不到非const
將如何更改結果。我無法在庫頭文件中找到特定的重載。
隨着鏗鏘我看到類似的結果,除了它使用xchg
,這是表達順序一致性的鏗鏘樣的方式。
有什麼可以解釋的區別?
我認爲在第二種情況下,編譯器可能決定[在目標體系結構上]簡單地發出圍欄比檢查使用的內存順序更有效,然後有條件地發出圍柵。 – Brian
@Brian +1。如果'my_order'將被聲明爲靜態和非常量,mfence可能會消失。 –
@Oleg這是一個很好的觀點。編譯器需要一個編譯時間常量才能對排序做出決定,而非靜態的非常量全局可能不符合條件 – LWimsey