Aracılığıyla paylaş


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 tutulması beklenmiyorsa, bekleyen bir iş parçacığının birkaç düzine veya birkaç yüz döngü boyunca kullanıcı modunda dönüp ardından kaynağı tekrar almaya çalışması daha verimli olabilir. Kaynak çalıştırıldıktan sonra kullanılabilir durumdaysa, birkaç bin döngü kaydetmiş olursunuz. Kaynak hala kullanılamıyorsa, sadece birkaç döngü harcamış olursunuz ve çekirdek tabanlı bir beklemeye hala geçebilirsiniz. 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öndürme işlemi tüm iş parçacıklarının ilerlemesini engellediği için iş parçacığının zaman diliminden hemen feragat eder. 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 bir SpinWait kullanıyorsanız, SpinWait'in kendisi bir bağlam değişimi başlatmadan önce çekirdek beklemesini çağırmanızı öneririz. SpinWait, her NextSpinWillYield çağrısından önce denetleyebileceğiniz SpinOnce özelliğini sağlar. Özellik true döndüğünde, kendi Bekleme işleminizi başlatın. Örnek için bkz SpinWait Kullanarak Two-Phase Bekleme İşlemi Nasıl Uygulanır.

İki aşamalı bir bekleme işlemi gerçekleştirmiyor, sadece bazı koşullar doğru olana kadar dönüyorsanız, SpinWait'ün bağlam geçişlerini gerçekleştirmesini etkinleştirerek Windows işletim sistemi ortamında uyumlu olmasını sağlayabilirsiniz. Aşağıdaki temel örnek, kilitsiz bir yığında SpinWait göstermektedir. Yüksek performans gerektiren ve iş parçacıkları açısından güvenli bir yığın gerekiyorsa, System.Collections.Concurrent.ConcurrentStack<T> kullanmayı düşünün.

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 bakınız