mscorlib(4.0.0.0) API with additions
SpinLock.cs
1 using System.Diagnostics;
5 
6 namespace System.Threading
7 {
9  [ComVisible(false)]
10  [DebuggerTypeProxy(typeof(SystemThreading_SpinLockDebugView))]
11  [DebuggerDisplay("IsHeld = {IsHeld}")]
12  [__DynamicallyInvokable]
13  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
14  public struct SpinLock
15  {
16  internal class SystemThreading_SpinLockDebugView
17  {
18  private SpinLock m_spinLock;
19 
20  public bool? IsHeldByCurrentThread
21  {
22  get
23  {
24  try
25  {
26  return m_spinLock.IsHeldByCurrentThread;
27  }
29  {
30  return null;
31  }
32  }
33  }
34 
35  public int? OwnerThreadID
36  {
37  get
38  {
39  if (m_spinLock.IsThreadOwnerTrackingEnabled)
40  {
41  return m_spinLock.m_owner;
42  }
43  return null;
44  }
45  }
46 
47  public bool IsHeld => m_spinLock.IsHeld;
48 
49  public SystemThreading_SpinLockDebugView(SpinLock spinLock)
50  {
51  m_spinLock = spinLock;
52  }
53  }
54 
55  private volatile int m_owner;
56 
57  private const int SPINNING_FACTOR = 100;
58 
59  private const int SLEEP_ONE_FREQUENCY = 40;
60 
61  private const int SLEEP_ZERO_FREQUENCY = 10;
62 
63  private const int TIMEOUT_CHECK_FREQUENCY = 10;
64 
65  private const int LOCK_ID_DISABLE_MASK = int.MinValue;
66 
67  private const int LOCK_ANONYMOUS_OWNED = 1;
68 
69  private const int WAITERS_MASK = 2147483646;
70 
71  private const int ID_DISABLED_AND_ANONYMOUS_OWNED = -2147483647;
72 
73  private const int LOCK_UNOWNED = 0;
74 
75  private static int MAXIMUM_WAITERS = 2147483646;
76 
79  [__DynamicallyInvokable]
80  public bool IsHeld
81  {
82  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
83  [__DynamicallyInvokable]
84  get
85  {
87  {
88  return m_owner != 0;
89  }
90  return (m_owner & 1) != 0;
91  }
92  }
93 
97  [__DynamicallyInvokable]
98  public bool IsHeldByCurrentThread
99  {
100  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
101  [__DynamicallyInvokable]
102  get
103  {
105  {
106  throw new InvalidOperationException(Environment.GetResourceString("SpinLock_IsHeldByCurrentThread"));
107  }
108  return (m_owner & int.MaxValue) == Thread.CurrentThread.ManagedThreadId;
109  }
110  }
111 
114  [__DynamicallyInvokable]
115  public bool IsThreadOwnerTrackingEnabled
116  {
117  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
118  [__DynamicallyInvokable]
119  get
120  {
121  return (m_owner & int.MinValue) == 0;
122  }
123  }
124 
127  [__DynamicallyInvokable]
128  public SpinLock(bool enableThreadOwnerTracking)
129  {
130  m_owner = 0;
131  if (!enableThreadOwnerTracking)
132  {
133  m_owner |= int.MinValue;
134  }
135  }
136 
141  [__DynamicallyInvokable]
142  public void Enter(ref bool lockTaken)
143  {
145  int owner = m_owner;
146  if (lockTaken || (owner & -2147483647) != int.MinValue || Interlocked.CompareExchange(ref m_owner, owner | 1, owner, ref lockTaken) != owner)
147  {
148  ContinueTryEnter(-1, ref lockTaken);
149  }
150  }
151 
156  [__DynamicallyInvokable]
157  public void TryEnter(ref bool lockTaken)
158  {
159  TryEnter(0, ref lockTaken);
160  }
161 
169  [__DynamicallyInvokable]
170  public void TryEnter(TimeSpan timeout, ref bool lockTaken)
171  {
172  long num = (long)timeout.TotalMilliseconds;
173  if (num < -1 || num > int.MaxValue)
174  {
175  throw new ArgumentOutOfRangeException("timeout", timeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
176  }
177  TryEnter((int)timeout.TotalMilliseconds, ref lockTaken);
178  }
179 
187  [__DynamicallyInvokable]
188  public void TryEnter(int millisecondsTimeout, ref bool lockTaken)
189  {
191  int owner = m_owner;
192  if (((millisecondsTimeout < -1) | lockTaken) || (owner & -2147483647) != int.MinValue || Interlocked.CompareExchange(ref m_owner, owner | 1, owner, ref lockTaken) != owner)
193  {
194  ContinueTryEnter(millisecondsTimeout, ref lockTaken);
195  }
196  }
197 
198  private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)
199  {
201  if (lockTaken)
202  {
203  lockTaken = false;
204  throw new ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));
205  }
206  if (millisecondsTimeout < -1)
207  {
208  throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
209  }
210  uint startTime = 0u;
211  if (millisecondsTimeout != -1 && millisecondsTimeout != 0)
212  {
213  startTime = TimeoutHelper.GetTime();
214  }
215  if (CdsSyncEtwBCLProvider.Log.IsEnabled())
216  {
217  CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner);
218  }
220  {
221  ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTime, ref lockTaken);
222  return;
223  }
224  int num = int.MaxValue;
225  int owner = m_owner;
226  if ((owner & 1) == 0)
227  {
228  Thread.BeginCriticalRegion();
229  if (Interlocked.CompareExchange(ref m_owner, owner | 1, owner, ref lockTaken) == owner)
230  {
231  return;
232  }
233  Thread.EndCriticalRegion();
234  }
235  else if ((owner & 0x7FFFFFFE) != MAXIMUM_WAITERS)
236  {
237  num = (Interlocked.Add(ref m_owner, 2) & 0x7FFFFFFE) >> 1;
238  }
239  if (millisecondsTimeout == 0 || (millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0))
240  {
241  DecrementWaiters();
242  return;
243  }
244  int processorCount = PlatformHelper.ProcessorCount;
245  if (num < processorCount)
246  {
247  int num2 = 1;
248  for (int i = 1; i <= num * 100; i++)
249  {
250  Thread.SpinWait((num + i) * 100 * num2);
251  if (num2 < processorCount)
252  {
253  num2++;
254  }
255  owner = m_owner;
256  if ((owner & 1) == 0)
257  {
258  Thread.BeginCriticalRegion();
259  int value = ((owner & 0x7FFFFFFE) == 0) ? (owner | 1) : ((owner - 2) | 1);
260  if (Interlocked.CompareExchange(ref m_owner, value, owner, ref lockTaken) == owner)
261  {
262  return;
263  }
264  Thread.EndCriticalRegion();
265  }
266  }
267  }
268  if (millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
269  {
270  DecrementWaiters();
271  return;
272  }
273  int num3 = 0;
274  while (true)
275  {
276  owner = m_owner;
277  if ((owner & 1) == 0)
278  {
279  Thread.BeginCriticalRegion();
280  int value2 = ((owner & 0x7FFFFFFE) == 0) ? (owner | 1) : ((owner - 2) | 1);
281  if (Interlocked.CompareExchange(ref m_owner, value2, owner, ref lockTaken) == owner)
282  {
283  return;
284  }
285  Thread.EndCriticalRegion();
286  }
287  if (num3 % 40 == 0)
288  {
289  Thread.Sleep(1);
290  }
291  else if (num3 % 10 == 0)
292  {
293  Thread.Sleep(0);
294  }
295  else
296  {
297  Thread.Yield();
298  }
299  if (num3 % 10 == 0 && millisecondsTimeout != -1 && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
300  {
301  break;
302  }
303  num3++;
304  }
305  DecrementWaiters();
306  }
307 
308  private void DecrementWaiters()
309  {
310  SpinWait spinWait = default(SpinWait);
311  while (true)
312  {
313  int owner = m_owner;
314  if ((owner & 0x7FFFFFFE) != 0 && Interlocked.CompareExchange(ref m_owner, owner - 2, owner) != owner)
315  {
316  spinWait.SpinOnce();
317  continue;
318  }
319  break;
320  }
321  }
322 
323  private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, uint startTime, ref bool lockTaken)
324  {
325  int num = 0;
326  int managedThreadId = Thread.CurrentThread.ManagedThreadId;
327  if (m_owner == managedThreadId)
328  {
329  throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
330  }
331  SpinWait spinWait = default(SpinWait);
332  while (true)
333  {
334  spinWait.SpinOnce();
335  if (m_owner == num)
336  {
337  Thread.BeginCriticalRegion();
338  if (Interlocked.CompareExchange(ref m_owner, managedThreadId, num, ref lockTaken) == num)
339  {
340  break;
341  }
342  Thread.EndCriticalRegion();
343  }
344  switch (millisecondsTimeout)
345  {
346  case 0:
347  return;
348  case -1:
349  continue;
350  }
351  if (spinWait.NextSpinWillYield && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
352  {
353  return;
354  }
355  }
356  }
357 
360  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
361  [__DynamicallyInvokable]
362  public void Exit()
363  {
364  if ((m_owner & int.MinValue) == 0)
365  {
366  ExitSlowPath(useMemoryBarrier: true);
367  }
368  else
369  {
370  Interlocked.Decrement(ref m_owner);
371  }
373  }
374 
378  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
379  [__DynamicallyInvokable]
380  public void Exit(bool useMemoryBarrier)
381  {
382  if ((m_owner & int.MinValue) != 0 && !useMemoryBarrier)
383  {
384  int owner = m_owner;
385  m_owner = (owner & -2);
386  }
387  else
388  {
389  ExitSlowPath(useMemoryBarrier);
390  }
392  }
393 
394  private void ExitSlowPath(bool useMemoryBarrier)
395  {
396  bool flag = (m_owner & int.MinValue) == 0;
397  if (flag && !IsHeldByCurrentThread)
398  {
399  throw new SynchronizationLockException(Environment.GetResourceString("SpinLock_Exit_SynchronizationLockException"));
400  }
401  if (useMemoryBarrier)
402  {
403  if (flag)
404  {
405  Interlocked.Exchange(ref m_owner, 0);
406  }
407  else
408  {
409  Interlocked.Decrement(ref m_owner);
410  }
411  }
412  else if (flag)
413  {
414  m_owner = 0;
415  }
416  else
417  {
418  int owner = m_owner;
419  m_owner = (owner & -2);
420  }
421  }
422  }
423 }
static Thread CurrentThread
Gets the currently running thread.
Definition: Thread.cs:134
void TryEnter(TimeSpan timeout, ref bool lockTaken)
Attempts to acquire the lock in a reliable manner, such that even if an exception occurs within the m...
Definition: SpinLock.cs:170
Provides a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop ...
Definition: SpinLock.cs:14
The exception that is thrown when a method requires the caller to own the lock on a given Monitor,...
Definition: __Canon.cs:3
The exception that is thrown when the value of an argument is outside the allowable range of values a...
double TotalMilliseconds
Gets the value of the current T:System.TimeSpan structure expressed in whole and fractional milliseco...
Definition: TimeSpan.cs:180
bool IsHeldByCurrentThread
Gets whether the lock is held by the current thread.
Definition: SpinLock.cs:99
Cer
Specifies a method's behavior when called within a constrained execution region.
Definition: Cer.cs:5
SecurityAction
Specifies the security actions that can be performed using declarative security.
Provides information about, and means to manipulate, the current environment and platform....
Definition: Environment.cs:21
static int CompareExchange(ref int location1, int value, int comparand)
Compares two 32-bit signed integers for equality and, if they are equal, replaces the first value.
void Exit()
Releases the lock.
Definition: SpinLock.cs:362
bool IsThreadOwnerTrackingEnabled
Gets whether thread ownership tracking is enabled for this instance.
Definition: SpinLock.cs:116
static void BeginCriticalRegion()
Notifies a host that execution is about to enter a region of code in which the effects of a thread ab...
static void EndCriticalRegion()
Notifies a host that execution is about to enter a region of code in which the effects of a thread ab...
The exception that is thrown when one of the arguments provided to a method is not valid.
SpinLock(bool enableThreadOwnerTracking)
Initializes a new instance of the T:System.Threading.SpinLock structure with the option to track thre...
Definition: SpinLock.cs:128
int ManagedThreadId
Gets a unique identifier for the current managed thread.
Definition: Thread.cs:55
Represents a time interval.To browse the .NET Framework source code for this type,...
Definition: TimeSpan.cs:12
The exception that is thrown when a method call is invalid for the object's current state.
void Enter(ref bool lockTaken)
Acquires the lock in a reliable manner, such that even if an exception occurs within the method call,...
Definition: SpinLock.cs:142
Consistency
Specifies a reliability contract.
Definition: Consistency.cs:5
void Exit(bool useMemoryBarrier)
Releases the lock.
Definition: SpinLock.cs:380
static int Decrement(ref int location)
Decrements a specified variable and stores the result, as an atomic operation.
Definition: Interlocked.cs:40
void TryEnter(int millisecondsTimeout, ref bool lockTaken)
Attempts to acquire the lock in a reliable manner, such that even if an exception occurs within the m...
Definition: SpinLock.cs:188
void TryEnter(ref bool lockTaken)
Attempts to acquire the lock in a reliable manner, such that even if an exception occurs within the m...
Definition: SpinLock.cs:157
Provides atomic operations for variables that are shared by multiple threads.
Definition: Interlocked.cs:10
bool IsHeld
Gets whether the lock is currently held by any thread.
Definition: SpinLock.cs:81
Creates and controls a thread, sets its priority, and gets its status.
Definition: Thread.cs:18