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 true
kendi 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