![](/img/trans.png)
[英]InterlockedCompareExchange64 vs std::atomic compare_exchange
[英]improve atomic read from InterlockedCompareExchange()
假設架構是 ARM64 或 x86-64。
我想確定這兩個是否等效:
a = _InterlockedCompareExchange64((__int64*)p, 0, 0);
MyBarrier(); a = *(volatile __int64*)p; MyBarrier();
其中MyBarrier()
是編譯器級別的內存屏障(提示),例如__asm__ __volatile__ ("" ::: "memory")
。 所以方法2應該比方法1快。
我聽說_Interlocked()
函數也意味着編譯器和硬件級別的內存障礙。
我聽說讀取(正確對齊)內部數據在這些架構上是原子的,但我不確定方法 2 是否可以廣泛使用?
(ps。因為我認為CPU會自動處理數據依賴,所以這里沒有太多考慮硬件障礙。)
感謝您對此提出任何建議/更正。
這是 Ivy Bridge(i5 筆記本電腦)上的一些基准測試。
(1E+006 循環: 27ms ):
; __int64 a = _InterlockedCompareExchange64((__int64*)p, 0, 0);
xor eax, eax
lock cmpxchg QWORD PTR val$[rsp], rbx
(1E+006 循環: 27ms ):
; __faststorefence(); __int64 a = *(volatile __int64*)p;
lock or DWORD PTR [rsp], 0
mov rcx, QWORD PTR val$[rsp]
(1E+006 循環: 7ms ):
; _mm_sfence(); __int64 a = *(volatile __int64*)p;
sfence
mov rcx, QWORD PTR val$[rsp]
(1E+006 循環: 1.26ms ,不同步?):
; __int64 a = *(volatile __int64*)p;
mov rcx, QWORD PTR val$[rsp]
要使第二個版本在功能上等效,您顯然需要原子 64 位讀取,這在您的平台上是正確的。
但是, _MemoryBarrier()
不是“對編譯器的提示”。 x86 上的_MemoryBarrier()
可防止編譯器和 CPU 重新排序,並確保寫入后的全局可見性。 您也可能只需要第一個_MemoryBarrier()
,第二個可以用_ReadWriteBarrier()
替換,除非a
也是共享變量 - 但您甚至不需要它,因為您正在讀取易失性指針,這將阻止MSVC 中的任何編譯器重新排序。
當你創建這個替換時,你基本上得到了幾乎相同的結果:
// a = _InterlockedCompareExchange64((__int64*)&val, 0, 0);
xor eax, eax
lock cmpxchg QWORD PTR __int64 val, r8 ; val
// _MemoryBarrier(); a = *(volatile __int64*)&val;
lock or DWORD PTR [rsp], r8d
mov rax, QWORD PTR __int64 val ; val
在我的 i7 Ivy Bridge 筆記本電腦上循環運行這兩個,得到相同的結果,在 2-3% 之內。
然而,有兩個內存屏障,“優化版本”實際上慢了大約 2 倍。
所以更好的問題是:你為什么要使用_InterlockedCompareExchange64
? 如果您需要對變量進行原子訪問,請使用std::atomic
,優化編譯器應將其編譯為最適合您的架構的版本,並添加所有必要的障礙以防止重新排序並確保緩存一致性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.