無鎖程式設計:lock-free原理
阿新 • • 發佈:2019-01-29
定義
無鎖程式設計是指在不使用鎖的情況下,在多執行緒環境下實現多變數的同步。即在沒有執行緒阻塞的情況下實現同步。這樣可以避免競態、死鎖等問題。
原理
CAS是指Compare-and-swap或Compare-and-Set
CAS是一個原子操作,用於多執行緒環境下的同步。它比較記憶體中的內容和給定的值,只有當兩者相同時(說明其未被修改),才會修改記憶體中的內容。
實現如下:
int compare_and_swap(int* reg, int oldval, int newval)
{
ATOMIC();
int old_reg_val = *reg ;
if (old_reg_val == oldval)
*reg = newval;
END_ATOMIC();
return old_reg_val;
}
或
bool compare_and_swap(int *accum, int *dest, int newval)
{
if (*accum == *dest) {
*dest = newval;
return true;
} else {
*accum = *dest;
return false;
}
}
返回bool值得好處是可以知道是否設定成功。
在實際環境中,使用的是:
bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval, type newval, ...)
在使用CAS時,需要先獲取操作變數的值並放到oldval中,之後呼叫cas函式,直到呼叫成功。例如給變數val賦值
while(true)
{
int oldval=val;
if(__sync_bool_compare_and_swap(&val , oldval, newval))
break;
}
ABA問題
在多執行緒環境中,使用lock-free的CAS時,如果一個執行緒對變數修改2次,第2次修改後的值和第1次修改前的值相同,那麼可能就會出現ABA問題。以上面的例子為例:
假設有兩個執行緒P1和P2,P1執行完int oldval=val
後被其他執行緒搶佔。P2執行緒在此期間修改了val的值(可能多次修改),但最終val的值和修改前一樣。當P1執行緒之後執行CAS函式時,並不能發現這個問題。這就是ABA問題。
解決方法
一個常用的方法是新增額外的“tag”或“stamp”位來標記是指標是否被修改過。