// repeatedly checking until the lock becomes available. As the thread remains active performing a non-useful task,
// the use of such a lock is a kind of busy waiting and consumes CPU resources without performing real work.
//
-//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-using System;
-using System.Security.Permissions;
+
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
namespace System.Threading
{
-
/// <summary>
/// Provides a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop
/// repeatedly checking until the lock becomes available.
/// concurrently.
/// </para>
/// </remarks>
- [ComVisible(false)]
[DebuggerTypeProxy(typeof(SystemThreading_SpinLockDebugView))]
[DebuggerDisplay("IsHeld = {IsHeld}")]
public struct SpinLock
// The waiters count is calculated by m_owner & WAITERS_MASK 01111....110
private static int MAXIMUM_WAITERS = WAITERS_MASK;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int CompareExchange(ref int location, int value, int comparand, ref bool success)
+ {
+ int result = Interlocked.CompareExchange(ref location, value, comparand);
+ success = (result == comparand);
+ return result;
+ }
+
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Threading.SpinLock"/>
/// structure with the option to track thread IDs to improve debugging.
int observedOwner = m_owner;
if (lockTaken || //invalid parameter
(observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired
- Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed
+ CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) //acquiring the lock failed
ContinueTryEnter(Timeout.Infinite, ref lockTaken); // Then try the slow path if any of the above conditions is met
-
}
/// <summary>
else
{
// Lock wasn't held; try to acquire it.
- Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken);
+ CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken);
}
}
if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
- nameof(timeout), timeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
+ nameof(timeout), timeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
}
// Call reliable enter with the int-based timeout milliseconds
if (millisecondsTimeout < -1 || //invalid parameter
lockTaken || //invalid parameter
(observedOwner & ID_DISABLED_AND_ANONYMOUS_OWNED) != LOCK_ID_DISABLE_MASK || //thread tracking is enabled or the lock is already acquired
- Interlocked.CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed
+ CompareExchange(ref m_owner, observedOwner | LOCK_ANONYMOUS_OWNED, observedOwner, ref lockTaken) != observedOwner) // acquiring the lock failed
ContinueTryEnter(millisecondsTimeout, ref lockTaken); // The call the slow pth
}
if (lockTaken)
{
lockTaken = false;
- throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));
+ throw new System.ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
}
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
- nameof(millisecondsTimeout), millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
+ nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
}
uint startTime = 0;
observedOwner = m_owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
- if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
{
// Aquired lock
return;
else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow
{
if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
- turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1 ;
+ turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1;
}
//***Step 2. Spinning
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Debug.Assert((newOwner & WAITERS_MASK) >= 0);
- if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Debug.Assert((newOwner & WAITERS_MASK) >= 0);
- if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
+ if (CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
}
spinner.SpinOnce();
}
-
}
/// <summary>
int lockUnowned = 0;
// We are using thread IDs to mark ownership. Snap the thread ID and check for recursion.
// We also must or the ID enablement bit, to ensure we propagate when we CAS it in.
- int m_newOwner = Thread.CurrentThread.ManagedThreadId;
+ int m_newOwner = Environment.CurrentManagedThreadId;
if (m_owner == m_newOwner)
{
// We don't allow lock recursion.
- throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
+ throw new LockRecursionException(SR.SpinLock_TryEnter_LockRecursionException);
}
// Loop until the lock has been successfully acquired or, if specified, the timeout expires.
do
{
-
// We failed to get the lock, either from the fast route or the last iteration
// and the timeout hasn't expired; spin once and try again.
spinner.SpinOnce();
if (m_owner == lockUnowned)
{
- if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
+ if (CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
{
return;
}
/// <exception cref="SynchronizationLockException">
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
/// </exception>
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit()
{
//This is the fast path for the thread tracking is disabled, otherwise go to the slow path
/// <exception cref="SynchronizationLockException">
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
/// </exception>
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit(bool useMemoryBarrier)
{
// This is the fast path for the thread tracking is diabled and not to use memory barrier, otherwise go to the slow path
if (threadTrackingEnabled && !IsHeldByCurrentThread)
{
throw new System.Threading.SynchronizationLockException(
- Environment.GetResourceString("SpinLock_Exit_SynchronizationLockException"));
+ SR.SpinLock_Exit_SynchronizationLockException);
}
if (useMemoryBarrier)
Interlocked.Exchange(ref m_owner, LOCK_UNOWNED);
else
Interlocked.Decrement(ref m_owner);
-
}
else
{
int tmpOwner = m_owner;
m_owner = tmpOwner & (~LOCK_ANONYMOUS_OWNED);
}
-
}
-
}
/// <summary>
/// </summary>
public bool IsHeld
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (IsThreadOwnerTrackingEnabled)
/// </exception>
public bool IsHeldByCurrentThread
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (!IsThreadOwnerTrackingEnabled)
{
- throw new InvalidOperationException(Environment.GetResourceString("SpinLock_IsHeldByCurrentThread"));
+ throw new InvalidOperationException(SR.SpinLock_IsHeldByCurrentThread);
}
- return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Thread.CurrentThread.ManagedThreadId);
+ return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Environment.CurrentManagedThreadId);
}
}
/// <summary>Gets whether thread ownership tracking is enabled for this instance.</summary>
public bool IsThreadOwnerTrackingEnabled
{
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get { return (m_owner & LOCK_ID_DISABLE_MASK) == 0; }
}