Megosztás:


SpinWait

System.Threading.SpinWait egy egyszerűsített szinkronizálási típus, amelyet alacsony szintű forgatókönyvekben használhat a kerneleseményekhez szükséges drága környezeti kapcsolók és kerneláttűnések elkerülése érdekében. Többmagos számítógépeken, ha egy erőforrás várhatóan hosszú ideig nem lesz tárolva, hatékonyabb lehet, ha egy várakozási szál felhasználói módban pörög néhány tucat vagy néhány száz cikluson át, majd újra megpróbálkozza az erőforrás beszerzését. Ha az erőforrás a forgás után elérhető, akkor több ezer ciklust takarított meg. Ha az erőforrás továbbra sem érhető el, akkor csak néhány ciklust töltött el, és még mindig beléphet egy kernel alapú várakozó állapotba. Ezt a pörgő-várakozás kombinációt néha kétfázisú várakozási műveletnek is nevezik.

SpinWait a kerneleseményeket burkoló .NET-típusokkal együtt használható, például ManualResetEvent. SpinWait önmagában is használható egyetlen program alapvető forgási funkcióihoz.

SpinWait több, mint egy üres hurok. Gondosan implementálva biztosítja az általános eset megfelelő pörgetési viselkedését, és maga is elindítja a környezeti kapcsolókat, ha elég hosszú ideig pörög (nagyjából a kernelváltáshoz szükséges idő). Egymagos számítógépeken például a szál időszeletét azonnal megadhatja, SpinWait mert a pörgetés blokkolja az előrehaladást az összes szálon. SpinWait többmagos gépeken is lehetővé teszi, hogy a várakozási szál ne blokkolja a magasabb prioritású szálakat vagy a szemétgyűjtőt. Ezért, ha kétfázisú várakozási műveletet használ SpinWait, javasoljuk, hogy a kernel várakozást hívjon meg, mielőtt SpinWait maga kezdeményez egy környezetváltást. SpinWaitmegadja a NextSpinWillYield tulajdonságot, amelyet minden hívás előtt ellenőrizhet.SpinOnce Amikor a tulajdonság visszatér true, indítsa el a saját várakozási műveletet. Példa : Útmutató: A SpinWait használata Two-Phase várakozási művelet implementálásához.

Ha nem hajt végre kétfázisú várakozási műveletet, hanem csak addig pörög, amíg bizonyos feltételek teljesülnek, engedélyezheti a SpinWait számára, hogy végrehajtsa a környezeti váltásokat, így helyesen működhessen a Windows operációs rendszer környezetében. Az alábbi alapszintű példa egy SpinWait zárolásmentes vermet mutat be. Ha magas teljesítményű, szálbiztos működésű vermet igényel, fontolja meg a System.Collections.Concurrent.ConcurrentStack<T> használatá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

Lásd még