簡體   English   中英

試圖寫一個無鎖的單鏈表,刪除麻煩

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM