[英]How Compare and Swap works
我讀過很多帖子說比較和交換保證原子性,但是我仍然不知道它是如何做到的。 下面是比較和交換的通用偽代碼:
int CAS(int *ptr,int oldvalue,int newvalue)
{
int temp = *ptr;
if(*ptr == oldvalue)
*ptr = newvalue
return temp;
}
這如何保證原子性? 例如,如果我使用它來實現互斥鎖,
void lock(int *mutex)
{
while(!CAS(mutex, 0 , 1));
}
這如何防止 2 個線程同時獲取互斥鎖? 任何指針將不勝感激。
“通用偽代碼”不是 CAS(比較和交換)實現的實際代碼。 特殊硬件指令用於激活 CPU 中的特殊原子硬件。 例如,在 x86 中,可以使用LOCK CMPXCHG
( http://en.wikipedia.org/wiki/Compare-and-swap )。
例如,在 gcc 中,內置了__sync_val_compare_and_swap()
- 它實現了特定於硬件的原子 CAS。 Paul E. McKenney ( Is Parallel Programming Hard, And, If So, What Can You Do About It?, 2014),第 4.3 節“原子操作”,第 31-32 頁對此操作進行了描述。
如果您想了解更多關於在原子操作之上構建更高級別的同步並從自旋鎖和主動自旋時燃燒 CPU 周期中拯救您的系統,您可以閱讀有關 Linux 中的futex
機制的一些內容。 關於 futexes 的第一篇論文是 Ulrich Drepper 2011 年發表的Futexes 是棘手的; 另一篇是 LWN 文章http://lwn.net/Articles/360699/ (歷史性文章是Fuss, Futexes 和 Furwocks: Fast Userland Locking in Linux ,2002)
Ulrich 描述的互斥鎖只使用原子操作來實現“快速路徑”(當互斥鎖沒有被鎖定並且我們的線程是唯一想要鎖定它的人時),但是如果互斥鎖被鎖定,線程將使用 futex( FUTEX_WAIT...)(它將使用原子操作標記互斥鎖變量,通知解鎖線程“有人在等待這個互斥鎖”,因此解鎖器將知道他必須使用 futex(FUTEX_WAKE, .. .)
它如何防止兩個線程獲取鎖? 好吧,一旦任何一個線程成功, *mutex
將為1
,因此任何其他線程的 CAS 都將失敗(因為它以預期值0
調用)。 通過在*mutex
存儲0
來釋放*mutex
。
請注意,這是 CAS 的一種奇怪用法,因為它本質上需要違反 ABA。 通常,您只需使用簡單的原子交換:
while (exchange(mutex, 1) == 1) { /* spin */ }
// critical section
*mutex = 0; // atomically
或者,如果您想稍微復雜一些並存儲有關哪個線程擁有鎖的信息,您可以使用 atomic-fetch-and-add 來做一些技巧(例如參見 Linux 內核自旋鎖代碼)。
您不能在 C 中實現 CAS。它是在匯編的硬件級別上完成的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.