다음을 통해 공유


스핀웨이트 (SpinWait)

System.Threading.SpinWait 는 낮은 수준의 시나리오에서 커널 이벤트에 필요한 값비싼 컨텍스트 스위치 및 커널 전환을 방지하기 위해 사용할 수 있는 간단한 동기화 유형입니다. 다중 코어 컴퓨터에서 리소스가 장기간 유지되지 않을 것으로 예상되는 경우 대기 중인 스레드가 수십 또는 수백 주기 동안 사용자 모드로 회전한 다음 리소스를 다시 획득하는 것이 더 효율적일 수 있습니다. 리소스가 회전 후 사용 가능하면 수천 개의 주기를 절약할 수 있습니다. 리소스를 아직 사용할 수 없는 경우, 몇 주기만 소비했으므로 커널 기반 대기에 진입할 수 있습니다. 이 회전 대기 조합은 2단계 대기 작업이라고도 합니다.

SpinWait 와 같은 ManualResetEvent커널 이벤트를 래핑하는 .NET 형식과 함께 사용하도록 설계되었습니다. SpinWait 는 하나의 프로그램에서만 기본 회전 기능에 사용할 수도 있습니다.

SpinWait 은 빈 루프 그 이상입니다. 일반적인 경우 올바른 회전 동작을 제공하기 위해 신중하게 구현되며, 충분히 길게 회전하는 경우(커널 전환에 필요한 대략적인 시간) 컨텍스트 스위치를 시작합니다. 예를 들어, 단일 코어 컴퓨터에서는 SpinWait가 스레드의 시간 할당을 즉시 포기합니다. 이는 스핀 대기가 다른 스레드의 진행을 차단하기 때문입니다. SpinWait 또한 대기 중인 스레드가 더 높은 우선순위의 스레드나 가비지 수집기를 차단하지 않도록 다중 코어 머신에서도 제어권을 양보합니다. 따라서 2단계 대기 작업에서 사용하는 SpinWait 경우 자체에서 컨텍스트 스위치를 시작하기 전에 SpinWait 커널 대기를 호출하는 것이 좋습니다. SpinWaitNextSpinWillYield 모든 호출 SpinOnce전에 확인할 수 있는 속성을 제공합니다. 속성이 true를 반환하면 대기 작업을 직접 시작합니다. 예를 들어 방법 : SpinWait을 사용하여 Two-Phase 대기 작업 구현을 참조하세요.

2단계 대기 작업을 수행하지 않고 일부 조건이 참이 될 때까지 회전하는 경우 SpinWait을(를) 활성화하여 Windows 운영 체제 환경에서 적절한 역할을 하도록 컨텍스트 전환을 수행할 수 있습니다. 다음 기본 예제에서는 SpinWait을(를) 잠금 없는 스택에서 보여줍니다. 고성능의 스레드로부터 안전한 스택이 필요한 경우 System.Collections.Concurrent.ConcurrentStack<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

참고하십시오