Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Threading / SpinLock.cs / 1305376 / SpinLock.cs
#pragma warning disable 0420
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// SpinLock.cs
// A spin lock is a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop ("spins")
// 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.Diagnostics;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Diagnostics.Contracts;
namespace System.Threading
{
///
/// 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.
///
///
///
/// Spin locks can be used for leaf-level locks where the object allocation implied by using a , in size or due to garbage collection pressure, is overly
/// expensive. Avoiding blocking is another reason that a spin lock can be useful, however if you expect
/// any significant amount of blocking, you are probably best not using spin locks due to excessive
/// spinning. Spinning can be beneficial when locks are fine grained and large in number (for example, a
/// lock per node in a linked list) as well as when lock hold times are always extremely short. In
/// general, while holding a spin lock, one should avoid blocking, calling anything that itself may
/// block, holding more than one spin lock at once, making dynamically dispatched calls (interface and
/// virtuals), making statically dispatched calls into any code one doesn't own, or allocating memory.
///
///
/// should only be used when it's been determined that doing so will improve an
/// application's performance. It's also important to note that is a value type,
/// for performance reasons. As such, one must be very careful not to accidentally copy a SpinLock
/// instance, as the two instances (the original and the copy) would then be completely independent of
/// one another, which would likely lead to erroneous behavior of the application. If a SpinLock instance
/// must be passed around, it should be passed by reference rather than by value.
///
///
/// Do not store instances in readonly fields.
///
///
/// All members of are thread-safe and may be used from multiple threads
/// concurrently.
///
///
[ComVisible(false)]
[HostProtection(Synchronization = true, ExternalThreading = true)]
[DebuggerTypeProxy(typeof(SystemThreading_SpinLockDebugView))]
[DebuggerDisplay("IsHeld = {IsHeld}")]
public struct SpinLock
{
// The current ownership state is a single signed int. There are two modes:
//
// 1) Ownership tracking enabled: the high bit is 0, and the remaining bits
// store the managed thread ID of the current owner. When the 31 low bits
// are 0, the lock is available.
// 2) Performance mode: when the high bit is 1, lock availability is indicated by the low bit.
// When the low bit is 1 -- the lock is held; 0 -- the lock is available.
//
// There are several masks and constants below for convenience.
private volatile int m_owner;
// The multiplier factor for the each spinning iteration
// This number has been chosen after trying different numbers on different CPUs (4, 8 and 16 ) and this provided the best results
private const int SPINNING_FACTOR = 100;
// After how many yields, call Sleep(1)
private const int SLEEP_ONE_FREQUENCY = 40;
// After how many yields, call Sleep(0)
private const int SLEEP_ZERO_FREQUENCY = 10;
// After how many yields, check the timeout
private const int TIMEOUT_CHECK_FREQUENCY = 10;
// Thr thread tracking disabled mask
private const int LOCK_ID_DISABLE_MASK = unchecked((int)0x80000000); //1000 0000 0000 0000 0000 0000 0000 0000
//the lock is held by some thread, but we don't know which
private const int LOCK_ANONYMOUS_OWNED = 0x1; //0000 0000 0000 0000 0000 0000 0000 0001
// Waiters mask if the thread tracking is disabled
private const int WAITERS_MASK = ~(LOCK_ID_DISABLE_MASK | 1); //0111 1111 1111 1111 1111 1111 1111 1110
// If the thread is unowned if:
// m_owner zero and the threa tracking is enabled
// m_owner & LOCK_ANONYMOUS_OWNED = zero and the thread tracking is disabled
private const int LOCK_UNOWNED = 0;
// The maximum number of waiters (only used if the thread tracking is disabled)
// The actual maximum waiters count is this number divided by two because each waiter increments the waiters count by 2
// The waiters count is calculated by m_owner & WAITERS_MASK 01111....110
private static int MAXIMUM_WAITERS = WAITERS_MASK;
///
/// Initializes a new instance of the
/// structure with the option to track thread IDs to improve debugging.
///
///
/// The default constructor for tracks thread ownership.
///
/// Whether to capture and use thread IDs for debugging
/// purposes.
public SpinLock(bool enableThreadOwnerTracking)
{
m_owner = LOCK_UNOWNED;
if (!enableThreadOwnerTracking)
{
m_owner |= LOCK_ID_DISABLE_MASK;
Contract.Assert(!IsThreadOwnerTrackingEnabled, "property should be false by now");
}
}
///
/// Initializes a new instance of the
/// structure with the option to track thread IDs to improve debugging.
///
///
/// The default constructor for tracks thread ownership.
///
///
/// Acquires the lock in a reliable manner, such that even if an exception occurs within the method
/// call, can be examined reliably to determine whether the lock was
/// acquired.
///
///
/// is a non-reentrant lock, meaning that if a thread holds the lock, it is
/// not allowed to enter the lock again. If thread ownership tracking is enabled (whether it's
/// enabled is available through ), an exception will be
/// thrown when a thread tries to re-enter a lock it already holds. However, if thread ownership
/// tracking is disabled, attempting to enter a lock already held will result in deadlock.
///
/// True if the lock is acquired; otherwise, false. must be initialized to false prior to calling this method.
///
/// Thread ownership tracking is enabled, and the current thread has already acquired this lock.
///
///
/// The argument must be initialized to false prior to calling Enter.
///
public void Enter(ref bool lockTaken)
{
if (lockTaken)
{
lockTaken = false;
throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));
}
// Fast path to acquire the lock if the lock is released
// If the thread tracking enabled set the new owner to the current thread id
// Id not, set the anonymous bit lock
int observedOwner = m_owner;
int newOwner = 0;
bool threadTrackingEnabled = (m_owner & LOCK_ID_DISABLE_MASK) == 0;
if (threadTrackingEnabled)
{
if (observedOwner == LOCK_UNOWNED)
newOwner = Thread.CurrentThread.ManagedThreadId;
}
else if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
newOwner = observedOwner | LOCK_ANONYMOUS_OWNED; // set the lock bit
}
if (newOwner != 0)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
// Fast path succeeded
return;
}
#endif
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
//Fast path failed, try slow path
ContinueTryEnter(Timeout.Infinite, ref lockTaken);
}
///
/// Attempts to acquire the lock in a reliable manner, such that even if an exception occurs within
/// the method call, can be examined reliably to determine whether the
/// lock was acquired.
///
///
/// Unlike , TryEnter will not block waiting for the lock to be available. If the
/// lock is not available when TryEnter is called, it will return immediately without any further
/// spinning.
///
/// True if the lock is acquired; otherwise, false. must be initialized to false prior to calling this method.
///
/// Thread ownership tracking is enabled, and the current thread has already acquired this lock.
///
///
/// The argument must be initialized to false prior to calling TryEnter.
///
public void TryEnter(ref bool lockTaken)
{
TryEnter(0, ref lockTaken);
}
///
/// Attempts to acquire the lock in a reliable manner, such that even if an exception occurs within
/// the method call, can be examined reliably to determine whether the
/// lock was acquired.
///
///
/// Unlike , TryEnter will not block indefinitely waiting for the lock to be
/// available. It will block until either the lock is available or until the
/// has expired.
///
/// A that represents the number of milliseconds
/// to wait, or a that represents -1 milliseconds to wait indefinitely.
///
/// True if the lock is acquired; otherwise, false. must be initialized to false prior to calling this method.
///
/// Thread ownership tracking is enabled, and the current thread has already acquired this lock.
///
///
/// The argument must be initialized to false prior to calling TryEnter.
///
/// is a negative
/// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater
/// than milliseconds.
///
public void TryEnter(TimeSpan timeout, ref bool lockTaken)
{
// Validate the timeout
Int64 totalMilliseconds = (Int64)timeout.TotalMilliseconds;
if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
{
throw new System.ArgumentOutOfRangeException(
"timeout", timeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
}
// Call reliable enter with the int-based timeout milliseconds
TryEnter((int)timeout.TotalMilliseconds, ref lockTaken);
}
///
/// Attempts to acquire the lock in a reliable manner, such that even if an exception occurs within
/// the method call, can be examined reliably to determine whether the
/// lock was acquired.
///
///
/// Unlike , TryEnter will not block indefinitely waiting for the lock to be
/// available. It will block until either the lock is available or until the has expired.
///
/// The number of milliseconds to wait, or (-1) to wait indefinitely.
/// True if the lock is acquired; otherwise, false. must be initialized to false prior to calling this method.
///
/// Thread ownership tracking is enabled, and the current thread has already acquired this lock.
///
///
/// The argument must be initialized to false prior to calling TryEnter.
///
/// is
/// a negative number other than -1, which represents an infinite time-out.
public void TryEnter(int millisecondsTimeout, ref bool lockTaken)
{
// validate input
if (lockTaken)
{
lockTaken = false;
throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));
}
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(
"millisecondsTimeout", millisecondsTimeout, Environment.GetResourceString("SpinLock_TryEnter_ArgumentOutOfRange"));
}
// Fast path to acquire the lock if the lock is released
// If the thread tracking enabled set the new owner to the current thread id
// Id not, set the anonymous bit lock
int observedOwner = m_owner;
int newOwner = 0;
if (IsThreadOwnerTrackingEnabled)
{
if (observedOwner == LOCK_UNOWNED)
newOwner = Thread.CurrentThread.ManagedThreadId;
}
else if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
newOwner = observedOwner | LOCK_ANONYMOUS_OWNED;
}
if (newOwner != 0)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
#endif
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
// Fast path failed, try slow path
ContinueTryEnter(millisecondsTimeout, ref lockTaken);
}
///
/// Try acquire the lock with long path, this is usually called after the first path in Enter and
/// TryEnter failed The reason for short path is to make it inline in the run time which improves the
/// performance. This method assumed that the parameter are validated in Enter ir TryENter method
///
/// The timeout milliseconds
/// The lockTaken param
private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)
{
long startTicks = 0;
if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)
{
startTicks = DateTime.UtcNow.Ticks;
}
#if !FEATURE_PAL && !FEATURE_CORECLR // PAL doesn't support eventing, and we don't compile CDS providers for Coreclr
if (CdsSyncEtwBCLProvider.Log.IsEnabled())
{
CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner);
}
#endif
if (IsThreadOwnerTrackingEnabled)
{
// Slow path for enabled thread tracking mode
ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTicks, ref lockTaken);
return;
}
// then thread tracking is disabled
// In this case there are three ways to acquire the lock
// 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2
// 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn
// the late the thread arrives the more it spins and less frequent it check the lock avilability
// Also the spins count is increaes each iteration
// If the spins iterations finished and failed to acquire the lock, go to step 3
// 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1)
// If the timeout is expired in after step 1, we need to decrement the waiters count before returning
int observedOwner;
//***Step 1, take the lock or update the waiters
// try to acquire the lock directly if possoble or update the waiters count
SpinWait spinner = new SpinWait();
while (true)
{
observedOwner = m_owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner) == observedOwner)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
#endif
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
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 || Interlocked.CompareExchange(ref m_owner, observedOwner + 2, observedOwner) == observedOwner)
break;
spinner.SpinOnce();
}
// Check the timeout.
if (millisecondsTimeout == 0 ||
(millisecondsTimeout != Timeout.Infinite &&
TimeoutExpired(startTicks, millisecondsTimeout)))
{
DecrementWaiters();
return;
}
//***Step 2. Spinning
//lock acquired failed and waiters updated
int turn = ((observedOwner + 2) & WAITERS_MASK) / 2;
int processorCount = PlatformHelper.ProcessorCount;
if (turn < processorCount)
{
int processFactor = 1;
for (int i = 1; i <= turn * SPINNING_FACTOR; i++)
{
Thread.SpinWait((turn + i) * SPINNING_FACTOR * processFactor);
if (processFactor < processorCount)
processFactor++;
observedOwner = m_owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero
observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Contract.Assert((newOwner & WAITERS_MASK) >= 0);
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
#endif
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
}
}
// Check the timeout.
if (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout))
{
DecrementWaiters();
return;
}
//*** Step 3, Yielding
//Sleep(1) every 50 yields
int yieldsoFar = 0;
while (true)
{
observedOwner = m_owner;
if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero
observedOwner | 1 // don't decrement it. just set the lock bit, it is zzero because a previous call of Exit(false) ehich corrupted the waiters
: (observedOwner - 2) | 1; // otherwise decrement the waiters and set the lock bit
Contract.Assert((newOwner & WAITERS_MASK) >= 0);
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
{
return;
}
#endif
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0)
{
Thread.Sleep(1);
}
else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0)
{
Thread.Sleep(0);
}
else
{
#if PFX_LEGACY_3_5
Platform.Yield();
#else
Thread.Yield();
#endif
}
if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0)
{
//Check the timeout.
if (millisecondsTimeout != Timeout.Infinite && TimeoutExpired(startTicks, millisecondsTimeout))
{
DecrementWaiters();
return;
}
}
yieldsoFar++;
}
}
///
/// decrements the waiters, in case of the timeout is expired
///
private void DecrementWaiters()
{
SpinWait spinner = new SpinWait();
while (true)
{
int observedOwner = m_owner;
if ((observedOwner & WAITERS_MASK) == 0) return; // don't decrement the waiters if it's corrupted by previous call of Exit(false)
if (Interlocked.CompareExchange(ref m_owner, observedOwner - 2, observedOwner) == observedOwner)
{
Contract.Assert(!IsThreadOwnerTrackingEnabled); // Make sure the waiters never be negative which will cause the thread tracking bit to be flipped
break;
}
spinner.SpinOnce();
}
}
///
/// ContinueTryEnter for the thread tracking mode enabled
///
private void ContinueTryEnterWithThreadTracking(int millisecondsTimeout, long startTicks, ref bool lockTaken)
{
Contract.Assert(IsThreadOwnerTrackingEnabled);
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;
if (m_owner == m_newOwner)
{
// We don't allow lock recursion.
throw new LockRecursionException(Environment.GetResourceString("SpinLock_TryEnter_LockRecursionException"));
}
SpinWait spinner = new SpinWait();
// 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();
// Test before trying to CAS, to avoid acquiring the line exclusively unnecessarily.
if (m_owner == lockUnowned)
{
#if !FEATURE_CORECLR
Thread.BeginCriticalRegion();
#endif
#if PFX_LEGACY_3_5
if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned) == lockUnowned)
{
lockTaken = true;
return;
}
#else
if (Interlocked.CompareExchange(ref m_owner, m_newOwner, lockUnowned, ref lockTaken) == lockUnowned)
{
return;
}
#endif
#if !FEATURE_CORECLR
// The thread failed to get the lock, so we don't need to remain in a critical region.
Thread.EndCriticalRegion();
#endif
}
// Check the timeout. We only RDTSC if the next spin will yield, to amortize the cost.
if (millisecondsTimeout == 0 ||
(millisecondsTimeout != Timeout.Infinite && spinner.NextSpinWillYield &&
TimeoutExpired(startTicks, millisecondsTimeout)))
{
return;
}
} while (true);
}
///
/// Helper function to validate the timeout
///
/// The start time in ticks
/// The orginal wait time
/// True if expired, false otherwise
private static bool TimeoutExpired(long startTicks, int originalWaitTime)
{
Contract.Assert(originalWaitTime != Timeout.Infinite);
long elapsedTicks = DateTime.UtcNow.Ticks - startTicks;
return (elapsedTicks >= (originalWaitTime * TimeSpan.TicksPerMillisecond));
}
///
/// Releases the lock.
///
///
/// The default overload of provides the same behavior as if calling using true as the argument.
///
///
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
///
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit()
{
Exit(true);
}
///
/// Releases the lock.
///
///
/// A Boolean value that indicates whether a memory fence should be issued in order to immediately
/// publish the exit operation to other threads.
///
///
/// Calling with the argument set to
/// true will improve the fairness of the lock at the expense of some performance. The default
/// overload behaves as if specifying true for .
///
///
/// Thread ownership tracking is enabled, and the current thread is not the owner of this lock.
///
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit(bool useMemoryBarrier)
{
if (IsThreadOwnerTrackingEnabled && !IsHeldByCurrentThread)
{
throw new System.Threading.SynchronizationLockException(
Environment.GetResourceString("SpinLock_Exit_SynchronizationLockException"));
}
if (useMemoryBarrier)
{
if (IsThreadOwnerTrackingEnabled)
Interlocked.Exchange(ref m_owner, LOCK_UNOWNED);
else
Interlocked.Decrement(ref m_owner);
}
else
{
if (IsThreadOwnerTrackingEnabled)
m_owner = LOCK_UNOWNED;
else
{
int tmpOwner = m_owner;
Contract.Assert((tmpOwner & LOCK_ANONYMOUS_OWNED) == LOCK_ANONYMOUS_OWNED, "The lock is not held.");
m_owner = tmpOwner - 1;
}
}
#if !FEATURE_CORECLR
Thread.EndCriticalRegion();
#endif
}
///
/// Gets whether the lock is currently held by any thread.
///
public bool IsHeld
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (IsThreadOwnerTrackingEnabled)
return m_owner != LOCK_UNOWNED;
return (m_owner & LOCK_ANONYMOUS_OWNED) != LOCK_UNOWNED;
}
}
///
/// Gets whether the lock is currently held by any thread.
///
///
/// Gets whether the lock is held by the current thread.
///
///
/// If the lock was initialized to track owner threads, this will return whether the lock is acquired
/// by the current thread. It is invalid to use this property when the lock was initialized to not
/// track thread ownership.
///
///
/// Thread ownership tracking is disabled.
///
public bool IsHeldByCurrentThread
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get
{
if (!IsThreadOwnerTrackingEnabled)
{
throw new InvalidOperationException(Environment.GetResourceString("SpinLock_IsHeldByCurrentThread"));
}
return ((m_owner & (~LOCK_ID_DISABLE_MASK)) == Thread.CurrentThread.ManagedThreadId);
}
}
/// Gets whether thread ownership tracking is enabled for this instance.
public bool IsThreadOwnerTrackingEnabled
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get { return (m_owner & LOCK_ID_DISABLE_MASK) == 0; }
}
#region Debugger proxy class
///
/// Internal class used by debug type proxy attribute to display the owner thread ID
///
internal class SystemThreading_SpinLockDebugView
{
// SpinLock object
private SpinLock m_spinLock;
///
/// SystemThreading_SpinLockDebugView constructor
///
/// The SpinLock to be proxied.
public SystemThreading_SpinLockDebugView(SpinLock spinLock)
{
// Note that this makes a copy of the SpinLock (struct). It doesn't hold a reference to it.
m_spinLock = spinLock;
}
///
/// Checks if the lock is held by the current thread or not
///
public bool? IsHeldByCurrentThread
{
get
{
try
{
return m_spinLock.IsHeldByCurrentThread;
}
catch (InvalidOperationException)
{
return null;
}
}
}
///
/// Gets the current owner thread, zero if it is released
///
public int? OwnerThreadID
{
get
{
if (m_spinLock.IsThreadOwnerTrackingEnabled)
{
return m_spinLock.m_owner;
}
else
{
return null;
}
}
}
///
/// Gets whether the lock is currently held by any thread or not.
///
public bool IsHeld
{
get { return m_spinLock.IsHeld; }
}
}
#endregion
}
}
#pragma warning restore 0420
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- X509CertificateTrustedIssuerElementCollection.cs
- IteratorDescriptor.cs
- StorageMappingFragment.cs
- DbConnectionPoolOptions.cs
- StrongNamePublicKeyBlob.cs
- CharacterHit.cs
- FontDifferentiator.cs
- xsdvalidator.cs
- WeakRefEnumerator.cs
- ToolBarTray.cs
- WebPartDisplayModeCancelEventArgs.cs
- HttpPostedFile.cs
- recordstatefactory.cs
- PackageRelationship.cs
- FontEmbeddingManager.cs
- BuildProvidersCompiler.cs
- SessionEndedEventArgs.cs
- DbConnectionPoolGroup.cs
- CodeGroup.cs
- SiteMapDataSource.cs
- HierarchicalDataTemplate.cs
- HtmlInputControl.cs
- basevalidator.cs
- TableLayoutPanel.cs
- LifetimeServices.cs
- ToolStripSplitStackLayout.cs
- RepeatInfo.cs
- CreateInstanceBinder.cs
- GenericXmlSecurityToken.cs
- SR.cs
- List.cs
- Semaphore.cs
- ConstructorExpr.cs
- Container.cs
- IndexerNameAttribute.cs
- TabletDeviceInfo.cs
- PowerModeChangedEventArgs.cs
- UnionCqlBlock.cs
- DependencyPropertyHelper.cs
- __FastResourceComparer.cs
- TraceContextEventArgs.cs
- D3DImage.cs
- InstanceHandle.cs
- KeySplineConverter.cs
- PEFileReader.cs
- OleAutBinder.cs
- TreeViewDataItemAutomationPeer.cs
- WebPartChrome.cs
- WeakRefEnumerator.cs
- TableParaClient.cs
- CuspData.cs
- ResourceExpressionBuilder.cs
- SubpageParaClient.cs
- AxisAngleRotation3D.cs
- CodePageEncoding.cs
- WebServiceEndpoint.cs
- SymLanguageType.cs
- Faults.cs
- OdbcConnectionFactory.cs
- GrammarBuilderWildcard.cs
- WebPartConnectionsEventArgs.cs
- MemberExpressionHelper.cs
- FormsAuthenticationModule.cs
- ColorDialog.cs
- ConstraintStruct.cs
- Adorner.cs
- CompilerTypeWithParams.cs
- ParameterCollection.cs
- EntitySetDataBindingList.cs
- TraceContextEventArgs.cs
- ProfileGroupSettings.cs
- NameTable.cs
- NullToBooleanConverter.cs
- DefaultSection.cs
- RepeaterCommandEventArgs.cs
- BevelBitmapEffect.cs
- LinkClickEvent.cs
- ContextStack.cs
- RawStylusInputCustomData.cs
- TypeBuilderInstantiation.cs
- DataGridTableCollection.cs
- ProxyWebPart.cs
- OdbcDataAdapter.cs
- Label.cs
- mongolianshape.cs
- Helpers.cs
- DataSourceBooleanViewSchemaConverter.cs
- PersonalizableTypeEntry.cs
- NonClientArea.cs
- ShimAsPublicXamlType.cs
- TextMetrics.cs
- AssemblyFilter.cs
- DeferredTextReference.cs
- DetailsViewRowCollection.cs
- FocusChangedEventArgs.cs
- EventMappingSettings.cs
- OleDbStruct.cs
- Nodes.cs
- ISFTagAndGuidCache.cs
- DynamicMethod.cs