SpinWait

System.Threading.SpinWait 是一个轻量同步类型,可以在低级别方案中使用它来避免内核事件所需的高开销的上下文切换和内核转换。 在多核计算机上,当预计资源不会保留很长一段时间时,如果让等待线程以用户模式旋转数十或数百个周期,然后重新尝试获取资源,则效率会更高。 如果在旋转后资源变为可用的,则可以节省数千个周期。 如果资源仍然不可用,则只花费了少量周期,并且仍然可以进行基于内核的等待。 这一旋转-等待的组合有时称为“两阶段等待操作”。

SpinWait 旨在与包装内核事件(例如 ManualResetEvent)的 .NET Framework 类型配合使用。 SpinWait 还可以自行用于仅限在一个程序中使用的基本旋转功能。

SpinWait 不仅仅是一个空循环。 它经过了精心实现,可以针对一般情况提供正确的旋转行为,而且还可以在旋转时间足够长(大致为内核转换所需的时间长度)的情况下自行启动上下文切换。 例如,在单核计算机上,SpinWait 会立即产生线程的时间片,因为旋转将阻塞所有线程向前进展。 SpinWait 甚至还会在多核计算机上产生线程的时间片以防止等待线程阻塞高优先级的线程或垃圾回收器。 因此,如果您在两阶段等待操作中使用 SpinWait,则建议您在 SpinWait 自行启动上下文切换之前调用内核等待。 SpinWait 提供 NextSpinWillYield 属性,您可在每次调用 SpinOnce 之前检查该属性。 当该属性返回 true 时,将启动您自己的等待操作。 有关示例,请参见如何:使用 SpinWait 实现两阶段等待操作

如果您不是在执行两阶段等待操作,而只是旋转等待某个条件为 true,则可使 SpinWait 执行它的上下文切换,以便它在 Windows 操作系统环境中是一个好公民。 下面的基本示例演示了无锁堆栈中的 SpinWait。 如果您需要高性能的线程安全的堆栈,请考虑使用 System.Collections.Concurrent.ConcurrentStack<T>

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
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();
        }
    }
}

请参见

参考

SpinWait

其他资源

线程处理对象和功能