网上演练
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.9 KiB

#if NET20 || NET30 || NET35 || !NET_4_6
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
using LinqInternal.Threading;
namespace System.Threading
{
[DebuggerDisplay("IsHeld = {IsHeld}")]
public struct SpinLock
{
private readonly bool _disableThreadTracking;
private int _isHeld;
private Thread _ownerThread;
public SpinLock(bool enableThreadOwnerTracking)
{
_disableThreadTracking = !enableThreadOwnerTracking;
_ownerThread = null;
_isHeld = 0;
}
public bool IsHeld
{
get { return Thread.VolatileRead(ref _isHeld) == 1; }
}
public bool IsHeldByCurrentThread
{
get
{
if (_disableThreadTracking)
{
throw new InvalidOperationException("Thread ownership tracking is disabled");
}
else
{
return IsHeld && ReferenceEquals(_ownerThread, Thread.CurrentThread);
}
}
}
public bool IsThreadOwnerTrackingEnabled
{
get { return _disableThreadTracking; }
}
public void Enter(ref bool lockTaken)
{
if (lockTaken)
{
lockTaken = false;
throw new ArgumentException();
}
else
{
if (_disableThreadTracking)
{
var check = Interlocked.CompareExchange(ref _isHeld, 1, 0);
if (check == 0)
{
lockTaken = true;
}
else
{
//Deadlock on recursion
TryEnter(-1, ref lockTaken);
}
}
else
{
if (IsHeldByCurrentThread)
{
//Throw on recursion
throw new LockRecursionException();
}
else
{
if (Interlocked.CompareExchange(ref _isHeld, 1, 0) == 0 && ReferenceEquals(Interlocked.CompareExchange(ref _ownerThread, Thread.CurrentThread, null), null))
{
lockTaken = true;
}
else
{
TryEnter(-1, ref lockTaken);
}
}
}
}
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit()
{
Exit(true);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void Exit(bool useMemoryBarrier)
{
if (_disableThreadTracking)
{
//Allow corruption: There is no check for what thread this is being called from
ExitExtracted(useMemoryBarrier);
}
else
{
if (IsHeldByCurrentThread)
{
ExitExtracted(useMemoryBarrier);
}
else
{
throw new SynchronizationLockException();
}
}
}
public void TryEnter(ref bool lockTaken)
{
if (lockTaken)
{
lockTaken = false;
throw new ArgumentException();
}
TryEnter(0, ref lockTaken);
}
public void TryEnter(TimeSpan timeout, ref bool lockTaken)
{
TryEnter((int)timeout.TotalMilliseconds, ref lockTaken);
}
public void TryEnter(int millisecondsTimeout, ref bool lockTaken)
{
if (_disableThreadTracking)
{
lockTaken |= ThreadingHelper.SpinWaitSet(ref _isHeld, 1, 0, millisecondsTimeout);
}
else
{
if (IsHeldByCurrentThread)
{
//Throw on recursion
throw new LockRecursionException();
}
else
{
lockTaken |= (ThreadingHelper.SpinWaitSet(ref _isHeld, 1, 0, millisecondsTimeout) && ReferenceEquals(Interlocked.CompareExchange(ref _ownerThread, Thread.CurrentThread, null), null));
}
}
}
private void ExitExtracted(bool useMemoryBarrier)
{
if (useMemoryBarrier)
{
Thread.VolatileWrite(ref _isHeld, 0);
Volatile.Write(ref _ownerThread, null);
}
else
{
_isHeld = 0;
_ownerThread = null;
}
}
}
}
#endif