Comment : activer le mode de suivi des threads dans le verrouillage Spinlock
System.Threading.SpinLock est un verrou d'exclusion mutuelle de bas niveau que vous pouvez utiliser pour les scénarios disposant de durées d'attente très courtes. SpinLock n'est pas ré-entrant. Une fois qu'un thread est entré dans le verrou, il doit le quitter correctement avant de pouvoir à nouveau entrer. En général, toute tentative de ré-entrer dans le verrou provoquerait un interblocage, et les interblocages peuvent être très difficiles à déboguer. Pour faciliter le développement, System.Threading.SpinLock prend en charge un mode de suivi de thread qui lève une exception lorsqu'un thread essaie de ré-entrer dans un verrou qu'il contient déjà. Cela vous permet de retrouver plus facilement le moment où le verrou n'a pas été quitté correctement. Vous pouvez activer le mode de suivi de thread à l'aide du constructeur SpinLock qui utilise un paramètre d'entrée booléen et en passant l'argument true. Une fois que vous avez terminé les phases de développement et de test, désactivez le mode de suivi de thread pour de meilleures performances.
Exemple
Voici un exemple de mode de suivi de thread. Les lignes qui permettent de quitter correctement le verrou sont commentées pour simuler une erreur de codage provoquant l'un des résultats suivants :
Une exception est levée si le SpinLock a été créé à l'aide de l'argument true (True en Visual Basic).
Interblocage si le SpinLock a été créé à l'aide de l'argument false (False en Visual Basic).
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();
}
}
}
}