title: SpinLock in C#. In which type of algorithm SpinLock is a better choice against Monitor?
body: <blockquote>
    <p><strong>Possible Duplicate:</strong><br>
    <a href="https://stackoverflow.com/questions/14611320/why-everyone-states-that-spinlock-is-faster">Why everyone states that SpinLock is faster?</a>  </p>
  </blockquote>
  
  
  
  <p>This question is concerning SpinLock, Monitor &amp; Interlocked.</p>
  
  <p>I made 2 tests which test the performance of <code>Monitor</code>, <code>SpinLock</code> and <code>Interlocked</code> and these tests have left me confused.</p>
  
  <p>My confusion is regarding particularly how fast <code>SpinLock</code> really is.
  According to my tests <code>SpinLock</code> is slower than <code>Monitor</code>.
  But based on a number of documents and articles <code>SpinLock</code> should provide performance gains.</p>
  
  <p>And now I wonder <strong>in which scenarios would <code>SpinLock</code> give a performance improvement?</strong></p>
  
  <p>Below you can find some details on tests I performed:</p>
  
  <p>In first test I created few threads (as many hardware threads I have) accessing the same shared lock object doing very short operation (or no operation at all: this is just a test).</p>
  
  <p>In second test I created an array of elements and few threads randomly accessing elements in this array. Each element contains its own locking object: <code>System.Object</code> for <code>Monitor</code> test, <code>SpinLock</code> object for <code>SpinLock</code> test, as for <code>Interlocked.Increment</code>, thread uses the public variable of type int inside the array element to perform <code>Interlocked.Increment</code> operation.</p>
  
  <p>In each test access to the shared region is performed in a loop.
  Each test consisted of 3 routines:</p>
  
  <ul>
  <li>Testing SpinLock</li>
  <li>Testing Monitor</li>
  <li>Testing Increment.Interlocked</li>
  </ul>
  
  <p>Each test showed that <code>SpinLock</code> was slower than <code>Monitor</code>.
  So, again the question that bothers me ever since I have performed mentioned tests is <strong>which scenarios are suitable for performance improvements given by <code>SpinLock</code></strong></p>
  
  <hr>
  
  <p><strong>Posting the code of the tests in order to give the details on it:</strong></p>
  
  <p>(Both tests were compiled against .net 4.5)</p>
  
  <p><strong>TEST 1, The threads are trying to gain exclusive access to the same shared locking object</strong></p>
  
  <pre><code>using System;
  using System.Collections.Concurrent;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Threading.Tasks;
  using System.Linq;
  using System.Globalization;
  using System.ComponentModel;
  using System.Threading;
  using System.Net.Sockets;
  using System.Net;
  
  class Program
  {
      static int _loopsCount = 1000000;
      static int _threadsCount = -1;
  
      static ProcessPriorityClass _processPriority = ProcessPriorityClass.RealTime;
      static ThreadPriority _threadPriority = ThreadPriority.Highest;
  
      static long _testingVar = 0;
  
  
      static void Main(string[] args)
      {
          _threadsCount = Environment.ProcessorCount;
          _threadsCount = (_threadsCount == 0) ? 1 : _threadsCount;
  
          Console.WriteLine("Cores/processors count: {0}", Environment.ProcessorCount);
          Console.WriteLine("Threads count: {0}", _threadsCount);
  
          Process.GetCurrentProcess().PriorityClass = _processPriority;
  
          TimeSpan tsInterlocked = ExecuteInterlocked();
          TimeSpan tsSpinLock = ExecuteSpinLock();
          TimeSpan tsMonitor = ExecuteMonitor();
  
          Console.WriteLine("Test with interlocked: {0} ms\r\nTest with SpinLock: {1} ms\r\nTest with Monitor: {2} ms",
              tsInterlocked.TotalMilliseconds,
              tsSpinLock.TotalMilliseconds,
              tsMonitor.TotalMilliseconds);
  
          Console.ReadLine();
      }
  
      static TimeSpan ExecuteInterlocked()
      {
          _testingVar = 0;
  
          ManualResetEvent _startEvent = new ManualResetEvent(false);
          CountdownEvent _endCountdown = new CountdownEvent(_threadsCount);
  
          Thread[] threads = new Thread[_threadsCount];
  
          for (int i = 0; i &lt; threads.Length; i++)
          {
              threads[i] = new Thread(() =&gt;
                  {
                      _startEvent.WaitOne();
  
                      for (int j = 0; j &lt; _loopsCount; j++)
                      {
                          Interlocked.Increment(ref _testingVar);
                      }
  
                      _endCountdown.Signal();
                  });
  
              threads[i].Priority = _threadPriority;
              threads[i].Start();
          }
  
          Stopwatch sw = Stopwatch.StartNew();
  
          _startEvent.Set();
          _endCountdown.Wait();
  
          return sw.Elapsed;
      }
  
      static SpinLock _spinLock = new SpinLock();
  
      static TimeSpan ExecuteSpinLock()
      {
          _testingVar = 0;
  
          ManualResetEvent _startEvent = new ManualResetEvent(false);
          CountdownEvent _endCountdown = new CountdownEvent(_threadsCount);
  
          Thread[] threads = new Thread[_threadsCount];
  
          for (int i = 0; i &lt; threads.Length; i++)
          {
              threads[i] = new Thread(() =&gt;
              {
                  _startEvent.WaitOne();
  
                  bool lockTaken;
  
                  for (int j = 0; j &lt; _loopsCount; j++)
                  {
                      lockTaken = false;
  
                      try
                      {
                          _spinLock.Enter(ref lockTaken);
  
                          _testingVar++;
                      }
                      finally
                      {
                          if (lockTaken)
                          {
                              _spinLock.Exit();
                          }
                      }
                  }
  
                  _endCountdown.Signal();
              });
  
              threads[i].Priority = _threadPriority;
              threads[i].Start();
          }
  
          Stopwatch sw = Stopwatch.StartNew();
  
          _startEvent.Set();
          _endCountdown.Wait();
  
          return sw.Elapsed;
      }
  
      static object _locker = new object();
  
      static TimeSpan ExecuteMonitor()
      {
          _testingVar = 0;
  
          ManualResetEvent _startEvent = new ManualResetEvent(false);
          CountdownEvent _endCountdown = new CountdownEvent(_threadsCount);
  
          Thread[] threads = new Thread[_threadsCount];
  
          for (int i = 0; i &lt; threads.Length; i++)
          {
              threads[i] = new Thread(() =&gt;
              {
                  _startEvent.WaitOne();
  
                  bool lockTaken;
  
                  for (int j = 0; j &lt; _loopsCount; j++)
                  {
                      lockTaken = false;
  
                      try
                      {
                          Monitor.Enter(_locker, ref lockTaken);
  
                          _testingVar++;
                      }
                      finally
                      {
                          if (lockTaken)
                          {
                              Monitor.Exit(_locker);
                          }
                      }
                  }
  
                  _endCountdown.Signal();
              });
  
              threads[i].Priority = _threadPriority;
              threads[i].Start();
          }
  
          Stopwatch sw = Stopwatch.StartNew();
  
          _startEvent.Set();
          _endCountdown.Wait();
  
          return sw.Elapsed;
      }
  }
  </code></pre>
  
  <p><strong>TEST 2, Threads are trying to gain exclusive access to the elements of array, which are picked randomly, i.e. test with the low contention</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace TestConcurrency
  {
      class Program
      {
          static int _loopsCount = 10000000;
          static int _threadsCount = -1;
          static int _arrayCount = 1000;
  
          static ProcessPriorityClass _processPriority = ProcessPriorityClass.RealTime;
          static ThreadPriority _threadPriority = ThreadPriority.Highest;
  
          static void Main(string[] args)
          {
              _threadsCount = Environment.ProcessorCount;
              _threadsCount = (_threadsCount == 0) ? 1 : _threadsCount;
  
              Console.WriteLine("Cores/processors count: {0}", Environment.ProcessorCount);
              Console.WriteLine("Threads count: {0}", _threadsCount);
  
              Process.GetCurrentProcess().PriorityClass = _processPriority;
  
              TimeSpan tsInterlocked = ExecuteInterlocked();
              TimeSpan tsSpinLock = ExecuteSpinLock();
              TimeSpan tsMonitor = ExecuteMonitor();
  
              Console.WriteLine("Test with interlocked: {0} ms\r\nTest with SpinLock: {1} ms\r\nTest with Monitor: {2} ms",
                  tsInterlocked.TotalMilliseconds,
                  tsSpinLock.TotalMilliseconds,
                  tsMonitor.TotalMilliseconds);
  
              Console.ReadLine();
          }
  
          static IEnumerable&lt;int&gt; newList()
          {
              return Enumerable.Range(0, _arrayCount);
          }
  
          static TimeSpan ExecuteMonitor()
          {
              ManualResetEvent _startEvent = new ManualResetEvent(false);
              CountdownEvent _endCountdown = new CountdownEvent(_threadsCount);
  
              Thread[] threads = new Thread[_threadsCount];
              var array = newList().Select(i =&gt; new ArrayElementForMonitor()).ToArray();
  
              for (int i = 0; i &lt; threads.Length; i++)
              {
                  int localI = i;
  
                  threads[i] = new Thread(() =&gt;
                  {
                      Random r = new Random(localI * localI * localI);
  
                      int index = 0;
  
                      _startEvent.WaitOne();
  
                      bool lockTaken;
  
                      for (int j = 0; j &lt; _loopsCount; j++)
                      {
                          index = r.Next(0, _arrayCount);
  
                          lockTaken = false;
  
                          try
                          {
                              Monitor.Enter(array[index].Locker, ref lockTaken);
                          }
                          finally
                          {
                              if (lockTaken)
                              {
                                  Monitor.Exit(array[index].Locker);
                              }
                          }
                      }
  
                      _endCountdown.Signal();
                  });
  
                  threads[i].Priority = _threadPriority;
                  threads[i].Start();
              }
  
              GC.Collect();
  
              Stopwatch sw = Stopwatch.StartNew();
  
              _startEvent.Set();
              _endCountdown.Wait();
  
              return sw.Elapsed;
          }
  
          static TimeSpan ExecuteSpinLock()
          {
              ManualResetEvent _startEvent = new ManualResetEvent(false);
              CountdownEvent _endCountdown = new CountdownEvent(_threadsCount);
  
              Thread[] threads = new Thread[_threadsCount];
              var array = newList().Select(i =&gt; new ArrayElementForSpinLock()).ToArray();
  
              for (int i = 0; i &lt; threads.Length; i++)
              {
                  int localI = i;
  
                  threads[i] = new Thread(() =&gt;
                  {
                      Random r = new Random(localI * localI * localI);
  
                      int index = 0;
  
                      _startEvent.WaitOne();
  
                      bool lockTaken;
  
                      for (int j = 0; j &lt; _loopsCount; j++)
                      {
                          index = r.Next(0, _arrayCount);
  
                          lockTaken = false;
  
                          try
                          {
                              array[index].Locker.Enter(ref lockTaken);
                          }
                          finally
                          {
                              if (lockTaken)
                              {
                                  array[index].Locker.Exit();
                              }
                          }
                      }
  
                      _endCountdown.Signal();
                  });
  
                  threads[i].Priority = _threadPriority;
                  threads[i].Start();
              }
  
              GC.Collect();
  
              Stopwatch sw = Stopwatch.StartNew();
  
              _startEvent.Set();
              _endCountdown.Wait();
  
              return sw.Elapsed;
          }
  
          static TimeSpan ExecuteInterlocked()
          {
              ManualResetEvent _startEvent = new ManualResetEvent(false);
              CountdownEvent _endCountdown = new CountdownEvent(_threadsCount);
  
              Thread[] threads = new Thread[_threadsCount];
              var array = newList().Select(i =&gt; new ArrayElementInterlocked()).ToArray();
  
              for (int i = 0; i &lt; threads.Length; i++)
              {
                  int localI = i;
  
                  threads[i] = new Thread(() =&gt;
                  {
                      Random r = new Random(localI * localI * localI);
  
                      int index = 0;
  
                      _startEvent.WaitOne();
  
                      for (int j = 0; j &lt; _loopsCount; j++)
                      {
                          index = r.Next(0, _arrayCount);
  
                          Interlocked.Increment(ref array[index].Element);
                      }
  
                      _endCountdown.Signal();
                  });
  
                  threads[i].Priority = _threadPriority;
                  threads[i].Start();
              }
  
              GC.Collect();
  
              Stopwatch sw = Stopwatch.StartNew();
  
              _startEvent.Set();
              _endCountdown.Wait();
  
              return sw.Elapsed;
          }
      }
  
      public class ArrayElementForMonitor
      {
          public object Locker = new object();
      }
  
      public class ArrayElementForSpinLock
      {
          public SpinLock Locker = new SpinLock();
      }
  
      public class ArrayElementInterlocked
      {
          public int Element;
      }
  }
  </code></pre>
  
  <hr>
  
  <p><strong>ADDITIONAL TEST 3. The test is executed in a single thread. The highest chances the thread to access the lock.</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace TestSimpleLocking
  {
      class Program
      {
          static int _loopsCount = 100000000;
  
          static ProcessPriorityClass _processPriority = ProcessPriorityClass.RealTime;
          static ThreadPriority _threadPriority = ThreadPriority.Highest;
  
          static void Main(string[] args)
          {
              Process.GetCurrentProcess().PriorityClass = _processPriority;
              Thread.CurrentThread.Priority = _threadPriority;
  
              TimeSpan tsInterlocked = ExecuteInterlocked();
              TimeSpan tsSpinLock = ExecuteSpinLock();
              TimeSpan tsMonitor = ExecuteMonitor();
  
              Console.WriteLine("Test with interlocked: {0} ms\r\nTest with SpinLock: {1} ms\r\nTest with Monitor: {2} ms",
                  tsInterlocked.TotalMilliseconds,
                  tsSpinLock.TotalMilliseconds,
                  tsMonitor.TotalMilliseconds);
  
              Console.ReadLine();
          }
  
          static TimeSpan ExecuteMonitor()
          {
              object locker = new object();
              int variable = 0;
  
              Stopwatch sw = Stopwatch.StartNew();
              bool lockTaken = false;
  
              for (int i = 0; i &lt; _loopsCount; i++)
              {
                  lockTaken = false;
  
                  try
                  {
                      Monitor.Enter(locker, ref lockTaken);
  
                      variable++;
                  }
                  finally
                  {
                      if (lockTaken)
                      {
                          Monitor.Exit(locker);
                      }
                  }
              }
  
              sw.Stop();
  
              Console.WriteLine(variable);
  
              return sw.Elapsed;
          }
  
          static TimeSpan ExecuteSpinLock()
          {
              SpinLock spinLock = new SpinLock();
              int variable = 0;
  
              Stopwatch sw = Stopwatch.StartNew();
  
              bool lockTaken = false;
  
              for (int i = 0; i &lt; _loopsCount; i++)
              {
                  lockTaken = false;
  
                  try
                  {
                      spinLock.Enter(ref lockTaken);
  
                      variable++;
                  }
                  finally
                  {
                      if (lockTaken)
                      {
                          spinLock.Exit();
                      }
                  }
              }
  
              sw.Stop();
  
              Console.WriteLine(variable);
  
              return sw.Elapsed;
          }
  
          static TimeSpan ExecuteInterlocked()
          {
              int variable = 0;
  
              Stopwatch sw = Stopwatch.StartNew();
  
              for (int i = 0; i &lt; _loopsCount; i++)
              {
                  Interlocked.Increment(ref variable);
              }
  
              sw.Stop();
  
              Console.WriteLine(variable);
  
              return sw.Elapsed;
          }
      }
  }
  </code></pre>
  
  <p>As far as I understand the 3rd test is the best case for the <code>SpinLock</code> choice. No contention at all. Single thread - sequenced execution.
  Why <code>SpinLock</code> is still far behind <code>Monitor</code>? Can anyone point me to some code which would prove me that <code>SpinLock</code> is useful at all (except device driver development)?</p>