Lezen in het Engels

Delen via


Procedure: Thread-Tracking-modus inschakelen in SpinLock

System.Threading.SpinLock is een wederzijdse uitsluitingsvergrendeling op laag niveau die u kunt gebruiken voor scenario's met zeer korte wachttijden. SpinLock is niet opnieuw in te treedt. Nadat een thread de vergrendeling heeft ingevoerd, moet deze de vergrendeling correct afsluiten voordat deze opnieuw kan worden ingevoerd. Normaal gesproken veroorzaakt elke poging om de vergrendeling opnieuw in te voeren een impasse en kunnen impasses erg moeilijk zijn om fouten op te sporen. Als hulpmiddel voor ontwikkeling System.Threading.SpinLock ondersteunt u een threadtraceringsmodus die ervoor zorgt dat er een uitzondering wordt gegenereerd wanneer een thread een vergrendeling probeert opnieuw in te voeren die al is opgeslagen. Hiermee kunt u gemakkelijker het punt vinden waarop de vergrendeling niet correct is afgesloten. U kunt de threadtraceringsmodus inschakelen met behulp van de SpinLock constructor die een Booleaanse invoerparameter gebruikt en een argument van true. Nadat u de ontwikkelings- en testfasen hebt voltooid, schakelt u de threadtrackingmodus uit voor betere prestaties.

Opmerking

In het volgende voorbeeld ziet u de modus threadtracking. De regels die de vergrendeling correct afsluiten, worden gemarkeerd om een coderingsfout te simuleren die een van de volgende resultaten veroorzaakt:

  • Er wordt een uitzondering gegenereerd als het SpinLock is gemaakt met behulp van een argument van true (True in Visual Basic).

  • Impasse als de is SpinLock gemaakt met behulp van een argument van false (False in Visual Basic).

C#
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();
            }
        }
    }
}

Zie ook