我是使用gcc內聯彙編的新手,並且想知道在x86多核計算機上是否可以實現自旋鎖(無競態條件)(使用AT & T語法):x86自旋鎖使用cmpxchg
spin_lock: mov 0 eax lock cmpxchg 1 [lock_addr] jnz spin_lock ret spin_unlock: lock mov 0 [lock_addr] ret
我是使用gcc內聯彙編的新手,並且想知道在x86多核計算機上是否可以實現自旋鎖(無競態條件)(使用AT & T語法):x86自旋鎖使用cmpxchg
spin_lock: mov 0 eax lock cmpxchg 1 [lock_addr] jnz spin_lock ret spin_unlock: lock mov 0 [lock_addr] ret
你有正確的想法,但你的彙編被打破:
cmpxchg
不能立即數工作,只註冊。
lock
不是mov
的有效前綴。 mov
到一個對齊的地址在x86上是原子的,所以你不需要lock
。
它已經有一段時間,因爲我已經使用AT & T語法,希望我記得一切:
spin_lock:
xorl %ecx, %ecx
incl %ecx
spin_lock_retry:
xorl %eax, %eax
lock; cmpxchgl %ecx, (lock_addr)
jnz spin_lock_retry
ret
spin_unlock:
movl $0 (lock_addr)
ret
注意,GCC有原子建宏,所以你實際上並不需要使用內聯彙編來做到這一點:
void spin_lock(int *p)
{
while(!__sync_bool_compare_and_swap(p, 0, 1));
}
void spin_unlock(int volatile *p)
{
asm volatile (""); // acts as a memory barrier.
*p = 0;
}
博下面說,鎖定指令產生費用:你使用任何人都必須刷新緩存並鎖定您的系統的內存總線,它可以是相當昂貴的,如果你有足夠的CPU。即使沒有很多的CPU,它仍然容易,值得各地優化:
void spin_lock(int volatile *p)
{
while(!__sync_bool_compare_and_swap(p, 0, 1))
{
while(*p) _mm_pause();
}
}
的pause
指令是對超線程CPU的性能至關重要,當你有一個不斷旋轉這樣的代碼 - 它可以讓第二個線程執行而第一個線程正在旋轉。在不支持pause
的CPU上,它被視爲nop
。
這將少放爭內存總線上:
void spin_lock(int *p)
{
while(!__sync_bool_compare_and_swap(p, 0, 1)) while(*p);
}
同意,但這段代碼不太好。一個簡單的while(* p)可以很容易地被編譯器優化。增加一些障礙。另外,爲英特爾芯片添加_mm_pause()可顯着提高性能。 –
應爲無效的用spin_lock參數()也聲明揮發性? – ManRow
編號'__sync_bool_compare_and_swap'已將其視爲'volatile'。 –
'spin_unlock'內用作內存屏障的asm應該包含內存clobber。另一方面,雖然'__sync_lock_release'被設計用來做「寫屏障,寫0」的東西,根本不需要考慮asm,它甚至「有點便攜」。它沒有明確地作爲讀取障礙(它在目標體系結構上完成),但沒關係。最糟糕的事情發生的另一個線程在罕見的情況下做一個額外的旋轉。 – Damon