[英]Why does memory_order_relaxed use atomic (lock-prefixed) instructions on x86?
在 Visual C++ 2013 上,當我編譯以下代碼時
#include <atomic>
int main()
{
std::atomic<int> v(2);
return v.fetch_add(1, std::memory_order_relaxed);
}
我在 x86 上取回以下程序集:
51 push ecx
B8 02 00 00 00 mov eax,2
8D 0C 24 lea ecx,[esp]
87 01 xchg eax,dword ptr [ecx]
B8 01 00 00 00 mov eax,1
F0 0F C1 01 lock xadd dword ptr [ecx],eax
59 pop ecx
C3 ret
同樣在 x64 上:
B8 02 00 00 00 mov eax,2
87 44 24 08 xchg eax,dword ptr [rsp+8]
B8 01 00 00 00 mov eax,1
F0 0F C1 44 24 08 lock xadd dword ptr [rsp+8],eax
C3 ret
我只是不明白:為什么一個int
變量的寬松增量需要一個lock
前綴?
這是有原因的,還是他們根本不包括刪除它的優化?
* 我使用/O2
和/NoDefaultLib
來修剪它並擺脫不必要的 C 運行時代碼,但這與問題無關。
因為它仍然需要一個鎖才能成為原子; 即使使用memory_order_relaxed
,遞增/遞減的要求也太嚴格而不能無鎖。
想象一下沒有鎖的情況。
v = 0;
然后我們生成 100 個線程,每個線程都使用以下命令:
v++;
然后你等待所有線程完成,你希望 v 是什么? 不幸的是,它可能不是 100。假設值 v=23 是由一個線程加載的,並且在創建 24 之前,另一個線程也加載了 23,然后也寫出了 24。 所以線程實際上相互否定。 這是因為增量本身不是原子的。 當然,加載、存儲、添加本身可能是原子的,但遞增是多個步驟,因此它不是原子的。
但是對於 std::atomic,無論std::memory_order
設置如何,所有操作都是原子的。 唯一的問題是它們將按什么順序發生。 memory_order_relaxed
仍然保證原子性,它可能會因為它附近發生的任何其他事情而亂序,即使對相同的值進行操作。
原子操作,即使是寬松的排序,仍然必須是原子的。
即使當前 CPU 上的某些操作是沒有lock
前綴的原子操作(提示:它們不是,由於多核緩存),也不能保證未來的 CPU 可以使用。
僅僅因為您想從二進制文件中優化一個字節,依賴於不屬於程序集規范的一部分(因此不能保證在未來的 x86_64 中保留)架構)
當然,在這種情況下,多核系統很普遍,因此您實際上需要一個lock
前綴才能在當前 CPU 上工作。 請參閱“int num”的 num++ 可以是原子的嗎?
首先,作為參考,考慮一個正常的分配。 它在 Intel/64 上生成以下內容:
// v = 10;
000000014000E0D0 mov eax,0Ah
000000014000E0D5 xchg eax,dword ptr [v (014001BCDCh)]
然后考慮一個輕松的任務:
// v.store(10, std::memory_order_relaxed);
000000014000E0D0 mov dword ptr [v (014001BCDCh)],0Ah
現在, std::atomic::fetch_add()
是一個讀-修改-寫操作,以“骯臟”的方式執行此操作毫無意義。 默認情況下,您根據http://en.cppreference.com/w/cpp/atomic/atomic/fetch_add獲取std::memory_order_seq_cst
。 因此,我認為,為此生成單個本機指令是有意義的。 至少在便宜的 Intel/64 上:
// v.fetch_add(1, std::memory_order_relaxed)
000000014000E0D0 mov eax,1
000000014000E0D5 lock xadd dword ptr [v (014001BCDCh)],eax
畢竟,您可以通過顯式編寫編譯器必須遵守的兩個操作來實現您想要的:
// auto x = v.load(std::memory_order_relaxed);
000000014000E0D0 mov eax,dword ptr [v (014001BCDCh)]
// ++x;
000000014000E0D6 inc eax
//v.store(x, std::memory_order_relaxed);
000000014000E0D8 mov dword ptr [v (014001BCDCh)],eax
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.