[英]Trying to write a lock-free singly linked list, trouble with the removal
我正在嘗試編寫一個無鎖的單鏈表。 最終的一致性不是問題(有人遍歷可能包含不正確項目的列表)。
我認為我得到了正確的添加項(循環和Interlocked.CompareExchange
)。
但我無法弄清楚如何刪除節點(列表中的任何位置),因為我必須獲取上一個項目,並將其Next
字段設置為當前節點的Next
字段。
class Node
{
Node Next;
object Value;
}
class SinglyLinkedList
{
Root _root;
public void Add(object value)
{}
public void Remove(object value)
{}
}
即
a - > b - > c
至
a - > c
偽代碼:
Node prev;
Node node = _root;
while (node.Value != nodeValue)
{
prev = node;
node = node.Next;
}
prev.Next = node.Next;
我如何使這成為一個原子操作(即確保調用prev.Next = node.Next
沒有next或prev被另一個線程刪除)?
我可以使用ReaderWriterLockSlim
,但我發現這個問題很有趣,因為我知道存在無鎖鏈表。
我的擔憂:
如果當前線程在循環和賦值之間掛起,則會發生以下情況:
prev
本身可能已被另一個線程刪除。 node
可能已被另一個線程刪除。 Node.Next
可能已被刪除 是的,添加是一個簡單的兩步循環,CAS在前一個.Next指針上; 但刪除很難!
實際上,如果不使用額外的信息和邏輯,你就無法做到。
Harris通過添加一個標記位來創建解決此問題的方法,該標記位曾禁止任何人修改節點。 刪除變為兩步:首先(CAS)標記被刪除的節點以防止任何人更改它(特別是它的.Next指針); 第二個CAS是前一個節點。下一個指針,現在是安全的,因為另一個節點已被標記。
問題是現在在C Harris中使用.Next指針的兩個最低有效位作為標記。 這很聰明,因為對於4字節對齊的指針,它們總是未被使用(即00),並且因為它們適合32位指針,所以它們可以原子地與指針本身一起使用CAS,這是該算法的關鍵。 當然,這在C#中是不可能的,至少在不使用不安全代碼的情況下。
解決方案稍微復雜一些,並涉及對包含兩個字段(.Next + marker)的不可變類的額外引用。
我沒有對這些想法進行冗長的解釋,而是在互聯網上找到了一些將引用您需要的所有細節的參考資料,請參閱:
無鎖鏈接列表(第1部分)解釋了問題;
無鎖鏈接列表(第2部分)解釋C解決方案+自旋鎖解決方案;
無鎖鏈接列表(第3部分)解釋不可變狀態引用;
如果您對該主題非常好奇,那么學術論文會提供各種解決方案並對其性能進行分析,例如:無鎖鏈接列表和跳過列表
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.