在多執行緒計算中,在同步期間會發生aba問題,當乙個位置被讀取兩次,兩次讀取具有相同的值,並且「值相同」用於指示「什麼都沒有改變」時。
但是,另乙個執行緒可以在兩次讀取之間執行並更改值,執行其他工作,然後將值改回,因此,即使第二個執行緒的工作違反了該假設,也使第乙個執行緒認為「什麼都沒有改變」。
當多個執行緒(或程序)訪問共享資料時,會發生aba問題。以下是將導致aba問題的事件序列:
儘管 p1 可以繼續執行,但是由於共享記憶體中的「隱藏」修改,因此行為可能不正確。
實現無鎖資料結構時,會遇到aba問題的常見情況:
如果從列表中刪除乙個專案,將其刪除,然後分配乙個新專案並將其新增到列表中;
由於mru記憶體分配,分配的物件通常與刪除的物件位於同一位置。因此,指向新專案的指標通常等於指向舊專案的指標,從而導致aba問題。
以下是乙個 lock-free 的棧的實現,但是它有 aba的問題。
/* ***** lock-free stack which suffers from aba problem.*/
class
stack
// the stack has changed, start over.}}
//// pushes the object specified by obj_ptr to stack.
//void
push
(obj* obj_ptr)
// the stack has changed, start over.}}
};
看以下事件序列:
假設棧初始的時候是這樣的: top -> a -> b -> c
thread 1 calls pop(), pop()實現的**片段如下:
ret_ptr = a;
next_ptr = ret_ptr-
>next;
// next_ptr is b
// <----- 被搶占
if(top_ptr.
compare_exchange_weak
(a, b)
)
注意,如上注釋所示,在執行 compare_exchange_weak()之前,thread_1 被 thread_2 搶占執行。
thread 2 搶占 thread 1 後,做了下面這些事:
pop()
;// the stack is top->b->c
pop();
// the stack is top->c
delete b;
push
(a);
// the stack is top->a->c
thread 1 拿回 cpu 繼續執行
compare_exchange_weak
(a, b)
此時,在compare_exchange_weak
內部做的比較(即比較 棧頂 與 ret_ptr), 會發現是相等的,因為現在棧頂就是 a.
所以,thread 1 就把棧頂設為了 b.
但是,b指標已經被 delete 了,在c++中,訪問這樣的野指標會導致未定義行為。 這將導致 crash,資料損壞,或者貌似工作正常。這樣的bug比較很難定位。
常見的解決方法是新增額外的「標籤」或「標記」位。例如,在指標上使用比較和交換的演算法可能會使用位址的低位來指示已成功修改指標的次數(注:這裡指的是 tagged pointer 的方法)。因此,即使位址相同,下一次比較和交換也將失敗,因為標記位將不匹配。由於第二個a與第乙個a略有不同,因此有時稱為aba』.
這樣的標記狀態引用也用於事務性儲存器中。儘管可以使用帶標記的指標來實現,但是如果可以使用雙倍寬度的cas,則首菜單獨的標記字段。
如果「標籤」字段迴繞,那麼針對aba的保證將不再有效。但是,已經觀察到,在當前現有的cpu上,並且使用60位標籤,只要程式壽命(即,不重新啟動程式)限制為10年,就不可能進行環繞。另外,有人說,出於實際目的,通常有40-48位的標籤就足夠了,以保證不會纏繞。由於現代cpu(特別是所有現代x64 cpu)傾向於支援128位cas操作,因此可以針對aba做出可靠保證。
理解ABA問題
所謂aba問題,就是比較並交換的迴圈,存在乙個時間差,而這個時間差可能帶來意想不到的問題。比如執行緒1和執行緒2同時也從記憶體取出a,執行緒t1將值從a改為b,然後又從b改為a。執行緒t2看到的最終值還是a,經過與預估值的比較,二者相等,可以更新,此時儘管執行緒t2的cas操作成功,但不代表就沒有問...
ABA問題及解決
aba問hiyi題 在多執行緒環境下,乙個執行緒需要修改共享變數的值,使用cas操作時,當其他執行緒將該共享變數由a該為b,再將b改為a後,這個執行緒依然可以cas操作成功,因為這個執行緒不能感知這個共享變數被修改過 解決方法 給共享變數增加乙個版本號,在cas操作時不僅比較值是否相等,還比較版本號...
CAS的ABA問題詳解
aba問題 執行緒1搶先獲得cpu時間片,而執行緒2因為其他原因阻塞了,執行緒1取值與期望的a值比較,發現相等然後將值更新為b,然後這個時候出現了執行緒3,期望值為b,欲更新的值為a,執行緒3取值與期望的值b比較,發現相等則將值更新為a,此時執行緒2從阻塞中恢復,並且獲得了cpu時間片,這時候執行緒...