共用方式為


SpinWait

System.Threading.SpinWait 是輕量型同步處理類型,您可以在低階案例中使用,以避免核心事件所需的昂貴內容切換和核心轉換。 在多核心計算機上,當不預期資源會被長時間佔用時,讓等候的線程在使用者模式中旋轉幾十個或幾百個週期,然後重試以取得資源,可能會更有效率。 如果資源可在旋轉之後使用,則您已儲存數千個週期。 如果資源仍然無法使用,則您只花費了幾個週期,而且仍然可以輸入以核心為基礎的等候。 這種旋轉等待組合有時稱為 兩階段等候作業

SpinWait 設計成與包裝核心事件的 .NET 類型搭配使用,例如 ManualResetEventSpinWait 也可以單獨用於一個程式中的基本旋轉功能。

SpinWait 不只是空迴圈。 仔細實作以提供一般案例的正確旋轉行為,而且如果其旋轉時間夠長(大約核心轉換所需的時間長度),則會自行起始內容切換。 例如,在單一核心計算機上,會立即產生線程的時間配量, SpinWait 因為旋轉會封鎖所有線程的向前進度。 SpinWait 也會在多核心計算機上運行,以免等待線程阻塞較高優先順序的線程或垃圾回收器。 因此,如果您在兩階段等候操作中使用 SpinWait ,建議您在 SpinWait 本身進行上下文切換之前叫用核心等待。 SpinWait 提供了 NextSpinWillYield 屬性,您可以在每次呼叫SpinOnce之前先檢查該NextSpinWillYield屬性。 起始您自己的等待操作,當屬性返回true時。 如需範例,請參閱 如何:使用SpinWait實作 Two-Phase 等候作業

如果您未執行兩階段等待操作,而只是處於某個條件成立之前進行自旋,您可以啟用 SpinWait 進行其上下文切換,以便其在 Windows 作業系統環境中更好地運行。 下列基本範例會在無鎖定堆疊中顯示 SpinWait 。 如果您需要高效能且安全線程的堆疊,請考慮使用 System.Collections.Concurrent.ConcurrentStack<T>

public class LockFreeStack<T>
{
    private volatile Node m_head;

    private class Node { public Node Next; public T Value; }

    public void Push(T item)
    {
        var spin = new SpinWait();
        Node node = new Node { Value = item }, head;
        while (true)
        {
            head = m_head;
            node.Next = head;
            if (Interlocked.CompareExchange(ref m_head, node, head) == head) break;
            spin.SpinOnce();
        }
    }

    public bool TryPop(out T result)
    {
        result = default(T);
        var spin = new SpinWait();

        Node head;
        while (true)
        {
            head = m_head;
            if (head == null) return false;
            if (Interlocked.CompareExchange(ref m_head, head.Next, head) == head)
            {
                result = head.Value;
                return true;
            }
            spin.SpinOnce();
        }
    }
}
Imports System.Threading

Module SpinWaitDemo


    Public Class LockFreeStack(Of T)
        Private m_head As Node

        Private Class Node
            Public [Next] As Node
            Public Value As T
        End Class

        Public Sub Push(ByVal item As T)
            Dim spin As New SpinWait()
            Dim head As Node, node As New Node With {.Value = item}

            While True
                Thread.MemoryBarrier()
                head = m_head
                node.Next = head
                If Interlocked.CompareExchange(m_head, node, head) Is head Then Exit While
                spin.SpinOnce()
            End While
        End Sub

        Public Function TryPop(ByRef result As T) As Boolean
            result = CType(Nothing, T)
            Dim spin As New SpinWait()

            Dim head As Node
            While True
                Thread.MemoryBarrier()
                head = m_head
                If head Is Nothing Then Return False
                If Interlocked.CompareExchange(m_head, head.Next, head) Is head Then
                    result = head.Value
                    Return True
                End If
                spin.SpinOnce()
            End While
        End Function
    End Class


End Module

另請參閱