Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

How to: Enable Thread-Tracking Mode in SpinLock

System.Threading.SpinLock is a low-level mutual exclusion lock that you can use for scenarios that have very short wait times. SpinLock is not re-entrant. After a thread enters the lock, it must exit the lock correctly before it can enter again. Typically, any attempt to re-enter the lock would cause deadlock, and deadlocks can be very difficult to debug. As an aid to development, System.Threading.SpinLock supports a thread-tracking mode that causes an exception to be thrown when a thread attempts to re-enter a lock that it already holds. This lets you more easily locate the point at which the lock was not exited correctly. You can turn on thread-tracking mode by using the SpinLock constructor that takes a Boolean input parameter, and passing in an argument of true. After you complete the development and testing phases, turn off thread-tracking mode for better performance.

Example

The following example demonstrates thread-tracking mode. The lines that correctly exit the lock are commented out to simulate a coding error that causes one of the following results:

  • An exception is thrown if the SpinLock was created by using an argument of true (True in Visual Basic).

  • Deadlock if the SpinLock was created by using an argument of false (False in Visual Basic).

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 {Thread.CurrentThread.ManagedThreadId} attempted to reenter the lock");
 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();
 }
 }
 }
}
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

See also


Feedback

Was this page helpful?

Additional resources