andrew4582

ReadWriteSpinLock

Feb 18th, 2011
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.43 KB | None | 0 0
  1. [StructLayout(LayoutKind.Sequential)]
  2. internal struct ReadWriteSpinLock
  3. {
  4.     private int _bits;
  5.     private int _id;
  6.     private static bool s_disableBusyWaiting;
  7.     private static readonly double[] s_backOffFactors;
  8.     private const int BACK_OFF_FACTORS_LENGTH = 13;
  9.     private const int WRITER_WAITING_MASK = 1073741824;
  10.     private const int WRITE_COUNT_MASK = 1073676288;
  11.     private const int READ_COUNT_MASK = 65535;
  12.     private const int WRITER_WAITING_SHIFT = 30;
  13.     private const int WRITE_COUNT_SHIFT = 16;
  14.     internal void AcquireReaderLock()
  15.     {
  16.         int hashCode = Thread.CurrentThread.GetHashCode();
  17.         if (!this._TryAcquireReaderLock(hashCode))
  18.         {
  19.             this._Spin(true, hashCode);
  20.         }
  21.     }
  22.  
  23.     internal void AcquireWriterLock()
  24.     {
  25.         int hashCode = Thread.CurrentThread.GetHashCode();
  26.         if (!this._TryAcquireWriterLock(hashCode))
  27.         {
  28.             this._Spin(false, hashCode);
  29.         }
  30.     }
  31.  
  32.     internal void ReleaseReaderLock()
  33.     {
  34.         Interlocked.Decrement(ref this._bits);
  35.     }
  36.  
  37.     internal void ReleaseWriterLock()
  38.     {
  39.         int bits = this._bits;
  40.         if (WriteLockCount(bits) == 1)
  41.         {
  42.             this._id = 0;
  43.         }
  44.         this.AlterWriteCountHoldingWriterLock(bits, -1);
  45.     }
  46.  
  47.     private static bool WriterWaiting(int bits)
  48.     {
  49.         return ((bits & 1073741824) != 0);
  50.     }
  51.  
  52.     private static int WriteLockCount(int bits)
  53.     {
  54.         return ((bits & 1073676288) >> 16);
  55.     }
  56.  
  57.     private static int ReadLockCount(int bits)
  58.     {
  59.         return (bits & 65535);
  60.     }
  61.  
  62.     private static bool NoWriters(int bits)
  63.     {
  64.         return ((bits & 1073676288) == 0);
  65.     }
  66.  
  67.     private static bool NoWritersOrWaitingWriters(int bits)
  68.     {
  69.         return ((bits & 2147418112) == 0);
  70.     }
  71.  
  72.     private static bool NoLocks(int bits)
  73.     {
  74.         return ((bits & -1073741825) == 0);
  75.     }
  76.  
  77.     private bool WriterWaiting()
  78.     {
  79.         return WriterWaiting(this._bits);
  80.     }
  81.  
  82.     private int WriteLockCount()
  83.     {
  84.         return WriteLockCount(this._bits);
  85.     }
  86.  
  87.     private int ReadLockCount()
  88.     {
  89.         return ReadLockCount(this._bits);
  90.     }
  91.  
  92.     private bool NoWriters()
  93.     {
  94.         return NoWriters(this._bits);
  95.     }
  96.  
  97.     private bool NoWritersOrWaitingWriters()
  98.     {
  99.         return NoWritersOrWaitingWriters(this._bits);
  100.     }
  101.  
  102.     private bool NoLocks()
  103.     {
  104.         return NoLocks(this._bits);
  105.     }
  106.  
  107.     private int CreateNewBits(bool writerWaiting, int writeCount, int readCount)
  108.     {
  109.         int num = (writeCount << 16) | readCount;
  110.         if (writerWaiting)
  111.         {
  112.             num |= 1073741824;
  113.         }
  114.         return num;
  115.     }
  116.  
  117.     private void AlterWriteCountHoldingWriterLock(int oldBits, int delta)
  118.     {
  119.         int readCount = ReadLockCount(oldBits);
  120.         int writeCount = WriteLockCount(oldBits) + delta;
  121.         while (true)
  122.         {
  123.             int num4 = this.CreateNewBits(WriterWaiting(oldBits), writeCount, readCount);
  124.             int num5 = Interlocked.CompareExchange(ref this._bits, num4, oldBits);
  125.             if (num5 == oldBits)
  126.             {
  127.                 return;
  128.             }
  129.             oldBits = num5;
  130.         }
  131.     }
  132.  
  133.     private bool _TryAcquireWriterLock(int threadId)
  134.     {
  135.         int num3;
  136.         int num4;
  137.         int num = this._id;
  138.         int oldBits = this._bits;
  139.         if (num == threadId)
  140.         {
  141.             this.AlterWriteCountHoldingWriterLock(oldBits, 1);
  142.             return true;
  143.         }
  144.         if ((num == 0) && NoLocks(oldBits))
  145.         {
  146.             num3 = this.CreateNewBits(false, 1, 0);
  147.             num4 = Interlocked.CompareExchange(ref this._bits, num3, oldBits);
  148.             if (num4 == oldBits)
  149.             {
  150.                 num = this._id;
  151.                 this._id = threadId;
  152.                 return true;
  153.             }
  154.             oldBits = num4;
  155.         }
  156.         if (!WriterWaiting(oldBits))
  157.         {
  158.             while (true)
  159.             {
  160.                 num3 = oldBits | 1073741824;
  161.                 num4 = Interlocked.CompareExchange(ref this._bits, num3, oldBits);
  162.                 if (num4 == oldBits)
  163.                 {
  164.                     break;
  165.                 }
  166.                 oldBits = num4;
  167.             }
  168.         }
  169.         return false;
  170.     }
  171.  
  172.     private bool _TryAcquireReaderLock(int threadId)
  173.     {
  174.         int bits = this._bits;
  175.         int num2 = this._id;
  176.         if (num2 == 0)
  177.         {
  178.             if (!NoWriters(bits))
  179.             {
  180.                 return false;
  181.             }
  182.         }
  183.         else if (num2 != threadId)
  184.         {
  185.             return false;
  186.         }
  187.         return (Interlocked.CompareExchange(ref this._bits, bits + 1, bits) == bits);
  188.     }
  189.  
  190.     private void _Spin(bool isReaderLock, int threadId)
  191.     {
  192.         int millisecondsTimeout = 0;
  193.         double num3 = s_backOffFactors[Math.Abs(threadId) % 13];
  194.         int num2 = (int) (4000.0 * num3);
  195.         num2 = Math.Max(Math.Min(10000, num2), 100);
  196.         DateTime utcNow = DateTime.UtcNow;
  197.         bool flag = s_disableBusyWaiting;
  198.     Label_0040:
  199.         if (isReaderLock)
  200.         {
  201.             if (this._TryAcquireReaderLock(threadId))
  202.             {
  203.                 return;
  204.             }
  205.         }
  206.         else if (this._TryAcquireWriterLock(threadId))
  207.         {
  208.             return;
  209.         }
  210.         if (flag)
  211.         {
  212.             Thread.Sleep(millisecondsTimeout);
  213.             millisecondsTimeout ^= 1;
  214.             goto Label_0040;
  215.         }
  216.         int num4 = num2;
  217.     Label_0069:
  218.         if (isReaderLock)
  219.         {
  220.             if (!this.NoWritersOrWaitingWriters())
  221.             {
  222.                 goto Label_007E;
  223.             }
  224.             goto Label_0040;
  225.         }
  226.         if (this.NoLocks())
  227.         {
  228.             goto Label_0040;
  229.         }
  230.     Label_007E:
  231.         if (--num4 < 0)
  232.         {
  233.             Thread.Sleep(millisecondsTimeout);
  234.             num2 /= 2;
  235.             num2 = Math.Max(num2, 100);
  236.             num4 = num2;
  237.             millisecondsTimeout ^= 1;
  238.         }
  239.         else
  240.         {
  241.             Thread.SpinWait(10);
  242.         }
  243.         goto Label_0069;
  244.     }
  245.  
  246.     static ReadWriteSpinLock()
  247.     {
  248.         s_disableBusyWaiting = SystemInfo.GetNumProcessCPUs() == 1;
  249.         s_backOffFactors = new double[] { 1.02, 0.965, 0.89, 1.065, 1.025, 1.115, 0.94, 0.995, 1.05, 1.08, 0.915, 0.98, 1.01 };
  250.     }
  251. }
Advertisement
Add Comment
Please, Sign In to add comment