簡體   English   中英

過度使用Interlocked.exchange?

[英]Overuse of Interlocked.exchange?

我試圖了解Interlocked.Exchange的正確用法,所以我正在實現具有添加和刪除功能的簡單排序的LinkedList。

如果這不是線程安全列表,顯然是要找到插入點,您將具有以下類似內容,以找到要插入的正確點,然后再插入新節點。

    public void Insert(int newValue)
    {
        var prev = _header;
        Node curr = _header.Next;

        while(curr != null && curr.value > newValue )
        {
            prev = curr;
            curr = curr.Next;
        }
        var newNode = new Node(newValue, curr);
        prev.Next = newNode;
    }

以下是我對如何為並發列表執行此操作的看法。 Interlocked.Exchange正在進行太多嗎? 沒有這個,插入是否仍然是線程安全的? 數百或數千個互鎖操作會導致性能下降嗎?

    public void InsertAsync(int newValue)
    {
        var prev = _header;
        Node curr = new Node(0, null);
        Interlocked.Exchange(ref curr, _header.Next);

        while (curr != null && curr.value > newValue)
        {
            prev = Interlocked.Exchange(ref curr, curr.Next);
        }
        //need some locking around prev.next first, ensure not modified/deleted, etc..
        //not in the scope of this question.
        var newNode = new Node(newValue, prev.Next);
        prev.Next = newNode;
    }

我知道,例如,curr = curr.next是原子讀取,但是我可以確定特定線程在沒有互鎖的情況下將讀取curr.next的最新值嗎?

使用Interlocked方法有兩件事:

  1. 它執行通常不是原子的一系列操作,並使它們有效地成為原子。 對於Exchange您可以執行以下操作: var temp = first; first=second; return temp; var temp = first; first=second; return temp; 但這樣做時,沒有任何風險被另一個線程修改的風險。
  2. 它引入了內存障礙。 編譯器,運行時和/或硬件優化可能會導致不同的線程具有本地“副本”值,該值在技術上位於共享內存中(通常是由於緩存變量)。 這可能導致一個線程花費很長時間才能“看到”另一線程中的寫入結果。 內存屏障實際上同步了同一變量的所有這些不同版本。

因此,專門針對您的代碼。 您的第二個解決方案實際上不是線程安全的。 每個單獨的Interlocked操作都是原子的,但是對各種Interlocked調用的任意數量的調用都不是原子的。 考慮到方法所執行的所有操作,實際上關鍵部分要大得多。 您將需要使用lock或其他類似的機制(即信號量或監視器)來將對代碼段的訪問限制為僅一個線程。 在您的特殊情況下,我想整個方法是關鍵部分。 如果您真的很謹慎,也許可以有幾個較小的關鍵區,但是要確保沒有可能出現的競賽條件將非常困難。

至於性能,因為代碼不起作用,因此性能無關緊要。

實現無鎖的鏈表比這要復雜得多。 我強烈建議您不要這樣做。 只需使用普通的舊顯示器即可。 如果只是出於興趣,那么您需要對無鎖算法進行一些研究。

為了更直接地回答您的問題,互鎖操作的成本取決於變量的爭用量。 在無競爭的情況下(例如單線程),成本極低。 隨着並發訪問次數的增加,成本也隨之增加。 原因是互鎖操作並非真正無鎖。 它只是使用硬件鎖而不是軟件鎖。 因此,無鎖算法的性能通常不如您所期望的那樣好。

您只是在保護分配,但是無論如何它們都是原子的。 您應該檢查Exchanged是否真的成功。

但這仍然不能使列表成為線程安全的,並發線程可能會在插入點之前插入一個比newValue大的新值。 我認為該列表甚至可能最終被打破。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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