共用方式為


SpinWait

System.Threading.SpinWait 是一個輕量型同步處理類型,您可以在低階案例中使用此類型,來避免核心事件所需且成本昂貴的環境切換和核心轉換。 在多核心電腦上,預期資源不會長時間保留時,若等待中的執行緒要在使用者模式中進行數十個或數百個週期的微調,然後進行重試以取得資源,此類型可能會更有效率。 如果資源在微調之後可供使用,則您節省了數千個週期。 如果資源仍然無法使用,則您只花費了數個週期,仍可進入以核心為基礎的等候。 這個微調然後等候的組合有時稱為「兩階段等候作業」

SpinWait 依設計可與 .NET 類型搭配使用,這些類型會包裝 ManualResetEvent 之類的核心事件。 SpinWait 也可單獨用來只在一個程式中進行基本微調功能。

SpinWait 不只是個空白迴圈。 謹慎地實作它以針對一般案例提供正確的調整行為,而且如果它微調的時間夠長 (大約是核心轉換所需的時間長度),將會自己起始環境切換。 例如,在單一核心電腦上,SpinWait 會立即產生執行緒的時間配量,因為微調區塊會轉送所有執行緒上的進度。 即使在多核心電腦上,SpinWait 也會產生以防止等候中的執行緒封鎖較高優先順序的執行緒或記憶體回收行程。 因此,如果您在兩階段等候作業中使用 SpinWait,我們建議您在 SpinWait 自己起始環境切換之前,先叫用核心等候。 SpinWait 提供 NextSpinWillYield 屬性,您可以在進行每個對 SpinOnce 的呼叫之前檢查此屬性。 當屬性傳回 true 時,起始您自己的等候作業。 如需範例,請參閱如何:使用 SpinWait 實作兩階段等候作業

如果您並未執行兩階段等候作業,而只是進行微調,直到某些條件成立,則您可以啟用 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

另請參閱