Csharp/CSharp Tutorial/Thread/Custom Lock

Материал из .Net Framework эксперт
Перейти к: навигация, поиск

A spin-lock

<source lang="csharp">/* Quote from Professional .NET Framework 2.0 (Programmer to Programmer) (Paperback) by Joe Duffy (Author)

  1. Paperback: 601 pages
  2. Publisher: Wrox (April 10, 2006)
  3. Language: English
  4. ISBN-10: 0764571354
  5. ISBN-13: 978-0764571350
  • /

using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime; using System.Runtime.rupilerServices; using System.Security; using System.Text; using System.Threading;

class SpinLock {

   private int state;
   private EventWaitHandle available = new AutoResetEvent(false);
   // This looks at the total number of hardware threads available; if it"s
   // only 1, we will use an optimized code path
   private static bool isSingleProc = (Environment.ProcessorCount == 1);
   private const int outerTryCount = 5;
   private const int cexTryCount = 100;
   public void Enter(out bool taken)
   {
       // Taken is an out parameter so that we set it *inside* the critical
       // region, rather than returning it and permitting aborts to creep in.
       // Without this, the caller could take the lock, but not release it
       // because it didn"t know it had to.
       taken = false;
       while (!taken)
       {
           if (isSingleProc)
           {
               // Don"t busy wait on 1-logical processor machines; try
               // a single swap, and if it fails, drop back to EventWaitHandle.
               Thread.BeginCriticalRegion();
               taken = Interlocked.rupareExchange(ref state, 1, 0) == 0;
               if (!taken)
                   Thread.EndCriticalRegion();
           }
           else
           {
               for (int i = 0; !taken && i < outerTryCount; i++)
               {
                   // Tell the CLR we"re in a critical region;
                   // interrupting could lead to deadlocks.
                   Thread.BeginCriticalRegion();
                   // Try "cexTryCount" times to CEX the state variable:
                   int tries = 0;
                   while (!(taken =
                       Interlocked.rupareExchange(ref state, 1, 0) == 0) &&
                       tries++ < cexTryCount)
                   {
                       Thread.SpinWait(1);
                   }
                   if (!taken)
                   {
                       // We failed to acquire in the busy spin, mark the end
                       // of our critical region and yield to let another
                       // thread make forward progress.
                       Thread.EndCriticalRegion();
                       Thread.Sleep(0);
                   }
               }
           }
           // If we didn"t acquire the lock, block.
           if (!taken) available.WaitOne();
       }
       return;
   }
   public void Enter()
   {
       // Convenience method. Using this could be prone to deadlocks.
       bool b;
       Enter(out b);
   }
   public void Exit()
   {
       if (Interlocked.rupareExchange(ref state, 0, 1) == 1)
       { 
           // We notify the waking threads inside our critical region so
           // that an abort doesn"t cause us to lose a pulse, (which could
           // lead to deadlocks).
           available.Set();
           Thread.EndCriticalRegion();
       }
   }

} public class MainClass {

   public static void Main()
   {
       SpinLock sl1 = new SpinLock();
       sl1.Enter();
       try
       {
           Console.WriteLine("Acquired the spin lock");
       }
       finally
       {
           sl1.Exit();
           Console.WriteLine("Released the spin lock");
       }
   }

}</source>

Acquired the spin lock
Released the spin lock