Como habilitar o modo de controle de thread em SpinLockHow to: Enable Thread-Tracking Mode in SpinLock

System.Threading.SpinLock é um bloqueio de exclusão mútua de baixo nível que você pode usar para cenários com tempos de espera muito curtos.System.Threading.SpinLock is a low-level mutual exclusion lock that you can use for scenarios that have very short wait times. O SpinLock não oferece reinserção.SpinLock is not re-entrant. Depois que um thread entra no bloqueio, ele deve sair do bloqueio corretamente antes de poder entrar novamente.After a thread enters the lock, it must exit the lock correctly before it can enter again. Normalmente, qualquer tentativa de reintroduzir o bloqueio causaria um deadlock, e os deadlocks podem ser muito difíceis de depurar.Typically, any attempt to re-enter the lock would cause deadlock, and deadlocks can be very difficult to debug. Como um auxílio ao desenvolvimento, o System.Threading.SpinLock suporta um modo de controle de thread que faz com que uma exceção seja acionada quando um thread tenta reintroduzir um bloqueio que ele já possui.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. Isso permite que você localize mais facilmente o ponto em que o bloqueio não foi encerrado corretamente.This lets you more easily locate the point at which the lock was not exited correctly. Você pode ativar o modo de controle de thread usando o construtor SpinLock que leva um parâmetro de entrada booleano e passando um argumento de true.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. Depois de concluir as fases de desenvolvimento e teste, desative o modo de controle de thread para um melhor desempenho.After you complete the development and testing phases, turn off thread-tracking mode for better performance.

ExemploExample

O exemplo a seguir demonstra o modo de controle de thread.The following example demonstrates thread-tracking mode. As linhas que saem corretamente do bloqueio são comentadas para simular um erro de codificação que causa um dos seguintes resultados:The lines that correctly exit the lock are commented out to simulate a coding error that causes one of the following results:

  • Uma exceção será lançada se o SpinLock foi criado usando um argumento de true (True no Visual Basic).An exception is thrown if the SpinLock was created by using an argument of true (True in Visual Basic).

  • Um deadlock se o SpinLock foi criado usando um argumento de false (False no 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 {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();

            }
        }
    }
}
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

Consulte tambémSee also