SpinWait

System.Threading.SpinWait , çekirdek olayları için gerekli olan pahalı bağlam anahtarlarından ve çekirdek geçişlerinden kaçınmak için düşük düzeyli senaryolarda kullanabileceğiniz basit bir eşitleme türüdür. Çok çekirdekli bilgisayarlarda, bir kaynağın uzun süre bekletilmesi beklenmediği durumlarda, bekleyen bir iş parçacığının birkaç düzine veya birkaç yüz döngü boyunca kullanıcı modunda dönmesi daha verimli olabilir ve sonra kaynağı almayı yeniden deneyebilir. Kaynak döndürildikten sonra kullanılabilir durumdaysa, birkaç bin döngü kaydetmişsiniz demektir. Kaynak hala kullanılamıyorsa, yalnızca birkaç döngü harcadıysanız ve yine de çekirdek tabanlı bekleme girebilirsiniz. Bu dönen ve sonra bekleyen birleşim bazen iki aşamalı bekleme işlemi olarak adlandırılır.

SpinWait gibi çekirdek olaylarını sarmalayan .NET türleriyle birlikte kullanılacak şekilde ManualResetEventtasarlanmıştır. SpinWait tek bir programda temel döndürme işlevselliği için kendi başına da kullanılabilir.

SpinWait boş bir döngüden fazlasıdır. Genel durum için doğru döndürme davranışı sağlamak üzere dikkatle uygulanır ve yeterince uzun süre dönerse bağlam anahtarlarını başlatır (kabaca çekirdek geçişi için gereken süre). Örneğin, tek çekirdekli bilgisayarlarda, SpinWait dönen tüm iş parçacıklarında ilerlemeyi engellediğinden, iş parçacığının zaman dilimini hemen verir. SpinWait ayrıca, bekleyen iş parçacığının daha yüksek öncelikli iş parçacıklarını veya çöp toplayıcıyı engellemesini önlemek için çok çekirdekli makinelerde bile verim sağlar. Bu nedenle, iki aşamalı bir bekleme işleminde kullanıyorsanız SpinWait , kendisi bir bağlam anahtarı başlatmadan önce çekirdek beklemesini SpinWait çağırmanızı öneririz. SpinWait , her çağrısından NextSpinWillYieldSpinOnceönce denetleyebileceğiniz özelliğini sağlar. özelliği döndürdüğünde truekendi Bekleme işleminizi başlatın. Örnek için bkz . Nasıl yapılır: İki Aşamalı Bekleme İşlemi Uygulamak için SpinWait Kullanma.

İki aşamalı bekleme işlemi gerçekleştirmiyor ancak yalnızca bazı koşullar doğru olana kadar dönüyorsanız, bağlam anahtarlarını windows işletim sistemi ortamında iyi bir vatandaş olacak şekilde gerçekleştirmeyi etkinleştirebilirsiniz SpinWait . Aşağıdaki temel örnekte, bir kilitsiz yığında gösterilmektedir SpinWait . Yüksek performanslı, iş parçacığı açısından güvenli bir yığına ihtiyacınız varsa kullanmayı System.Collections.Concurrent.ConcurrentStack<T>göz önünde bulundurun.

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

Ayrıca bkz.