방법: 스핀 잠금에서 스레드-추적 모드 사용
System.Threading.SpinLock은 대기 시간이 매우 짧은 시나리오에서 사용할 수 있는 하위 수준 상호 제외 잠금입니다. SpinLock은 다시 시작할 수 없습니다. 스레드가 이미 획득된 잠금을 다시 잠그려면 먼저 잠금을 올바르게 종료해야 합니다. 일반적으로 이미 획득된 잠금을 다시 잠그려고 하면 디버깅하기 매우 어려울 수 있는 교착 상태가 발생할 수 있습니다. 개발 단계를 위해 System.Threading.SpinLock에서는 스레드가 이미 획득한 잠금을 다시 잠그려고 하면 예외를 throw하는 스레드 추적 모드를 지원합니다. 이 기능을 사용하면 잠금이 올바르게 종료되지 않은 지점을 보다 쉽게 찾을 수 있습니다. SpinLock 생성자를 사용하여 부울 입력 매개 변수를 받아서 true의 인수에 전달하여 스레드 추적 모드를 설정할 수 있습니다. 개발 및 테스트 단계를 완료한 후에는 보다 나은 성능을 위해 스레드 추적 모드를 해제합니다.
예제
다음 예제에서는 스레드 추적 모드를 보여 줍니다. 잠금을 올바르게 종료하는 줄은 다음 결과 중 하나를 생성하는 코딩 오류를 시뮬레이션하도록 주석 처리됩니다.
true(Visual Basic의 경우 True)의 인수를 사용하여 SpinLock을 만든 경우 예외가 throw됩니다.
false(Visual Basic의 경우 False)의 인수를 사용하여 SpinLock을 만든 경우 교착 상태가 발생합니다.
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Module Module1
Public Class SpinTest
' True means "enable thread tracking." This will cause an
' exception to be thrown when the first thread attempts to reenter the lock.
' Specify False to cause deadlock due to coding error below.
Private Shared _spinLock = New SpinLock(True)
Public Shared Sub Main()
Parallel.Invoke(
Sub() DoWork(),
Sub() DoWork(),
Sub() DoWork(),
Sub() DoWork()
)
Console.WriteLine("Press any key.")
Console.ReadKey()
End Sub
Public Shared Sub DoWork()
Dim sb = New StringBuilder()
For i As Integer = 1 To 9999
Dim lockTaken As Boolean = False
Try
_spinLock.Enter(lockTaken)
' do work here protected by the lock
Thread.SpinWait(50000)
sb.Append(Thread.CurrentThread.ManagedThreadId)
sb.Append(" Entered-")
Catch ex As LockRecursionException
Console.WriteLine("Thread {0} attempted to reenter the lock",
Thread.CurrentThread.ManagedThreadId)
Throw
Finally
' INTENTIONAL CODING ERROR TO DEMONSTRATE THREAD TRACKING!
' UNCOMMENT THE LINES FOR CORRECT SPINLOCK BEHAVIOR
' Commenting out these lines causes the same thread
' to attempt to reenter the lock. If the SpinLock was
' created with thread tracking enabled, the exception
' is thrown. Otherwise, if the SpinLock was created with a
' parameter of false, and these lines are left commented, the spinlock deadlocks.
If (lockTaken) Then
' _spinLock.Exit()
' sb.Append("Exited ")
End If
End Try
' Output for diagnostic display.
If (i Mod 4 <> 0) Then
Console.Write(sb.ToString())
Else
Console.WriteLine(sb.ToString())
End If
sb.Clear()
Next
End Sub
End Class
End Module
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SpinLockDemo
{
// C#
public class SpinLockTest
{
// Specify true to enable thread tracking. This will cause
// exception to be thrown when the first thread attempts to reenter the lock.
// Specify false to cause deadlock due to coding error below.
private static SpinLock _spinLock = new SpinLock(true);
static void Main()
{
Parallel.Invoke(
() => DoWork(),
() => DoWork(),
() => DoWork(),
() => DoWork()
);
Console.WriteLine("Press any key.");
Console.ReadKey();
}
public static void DoWork()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++)
{
bool lockTaken = false;
try
{
_spinLock.Enter(ref lockTaken);
// do work here protected by the lock
Thread.SpinWait(50000);
sb.Append(Thread.CurrentThread.ManagedThreadId);
sb.Append(" Entered-");
}
catch (LockRecursionException ex)
{
Console.WriteLine("Thread {0} attempted to reenter the lock",
Thread.CurrentThread.ManagedThreadId);
throw;
}
finally
{
// INTENTIONAL CODING ERROR TO DEMONSTRATE THREAD TRACKING!
// UNCOMMENT THE LINES FOR CORRECT SPINLOCK BEHAVIOR
// Commenting out these lines causes the same thread
// to attempt to reenter the lock. If the SpinLock was
// created with thread tracking enabled, the exception
// is thrown. Otherwise the spinlock deadlocks.
if (lockTaken)
{
// _spinLock.Exit(false);
// sb.Append("Exited ");
}
}
// Output for diagnostic display.
if(i % 4 != 0)
Console.Write(sb.ToString());
else
Console.WriteLine(sb.ToString());
sb.Clear();
}
}
}
}