36 [StructLayout(LayoutKind.Explicit)]
37 internal struct TicketType {
39 public long TotalValue;
51 [
System.Diagnostics.DebuggerDisplay (
"IsHeld = {IsHeld}")]
52 [
System.Diagnostics.DebuggerTypeProxy (
"System.Threading.SpinLock+SystemThreading_SpinLockDebugView")]
60 static readonly Watch sw = Watch.StartNew ();
64 public bool IsThreadOwnerTrackingEnabled {
66 return isThreadOwnerTrackingEnabled;
73 long totalValue = ticket.TotalValue;
74 return (totalValue >> 32) != (totalValue & 0xFFFFFFFF);
78 public bool IsHeldByCurrentThread {
80 if (isThreadOwnerTrackingEnabled)
81 return IsHeld && Thread.CurrentThread.ManagedThreadId == threadWhoTookLock;
94 public SpinLock (
bool enableThreadOwnerTracking)
96 this.isThreadOwnerTrackingEnabled = enableThreadOwnerTracking;
97 this.threadWhoTookLock = 0;
98 this.ticket =
new TicketType ();
117 [MonoTODO (
"Not safe against async exceptions")]
118 public void Enter (ref
bool lockTaken)
121 throw new ArgumentException (
"lockTaken",
"lockTaken must be initialized to false");
122 if (isThreadOwnerTrackingEnabled && IsHeldByCurrentThread)
123 throw new LockRecursionException ();
127 RuntimeHelpers.PrepareConstrainedRegions ();
129 slot = Interlocked.Increment (ref ticket.Users) - 1;
132 while (slot != ticket.Value) {
135 while (stallTickets != null && stallTickets.
TryRemove (ticket.Value))
139 if (slot == ticket.Value) {
141 threadWhoTookLock = Thread.CurrentThread.ManagedThreadId;
142 }
else if (slot != -1) {
144 if (stallTickets == null)
146 stallTickets.TryAdd (slot);
153 TryEnter (0, ref lockTaken);
156 public void TryEnter (TimeSpan timeout, ref
bool lockTaken)
158 TryEnter ((
int)timeout.TotalMilliseconds, ref lockTaken);
161 public void TryEnter (
int millisecondsTimeout, ref
bool lockTaken)
163 if (millisecondsTimeout < -1)
164 throw new ArgumentOutOfRangeException (
"milliSeconds",
"millisecondsTimeout is a negative number other than -1");
166 throw new ArgumentException (
"lockTaken",
"lockTaken must be initialized to false");
167 if (isThreadOwnerTrackingEnabled && IsHeldByCurrentThread)
168 throw new LockRecursionException ();
170 long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
174 while (stallTickets != null && stallTickets.
TryRemove (ticket.Value))
177 long u = ticket.Users;
178 long totalValue = (u << 32) | u;
180 = BitConverter.IsLittleEndian ? (u << 32) | (u + 1) : ((u + 1) << 32) | u;
182 RuntimeHelpers.PrepareConstrainedRegions ();
185 lockTaken = Interlocked.CompareExchange (ref ticket.TotalValue, newTotalValue, totalValue) == totalValue;
188 threadWhoTookLock = Thread.CurrentThread.ManagedThreadId;
192 }
while (!stop && (millisecondsTimeout == -1 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout));
195 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
201 [ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
202 public void Exit (
bool useMemoryBarrier)
204 RuntimeHelpers.PrepareConstrainedRegions ();
207 if (isThreadOwnerTrackingEnabled && !IsHeldByCurrentThread)
208 throw new SynchronizationLockException (
"Current thread is not the owner of this lock");
210 threadWhoTookLock =
int.MinValue;
212 if (useMemoryBarrier)
213 Interlocked.Increment (ref ticket.Value);
216 }
while (stallTickets != null && stallTickets.
TryRemove (ticket.Value));
void TryEnter(TimeSpan timeout, ref bool lockTaken)
readonly bool isThreadOwnerTrackingEnabled
ConcurrentOrderedList< int > stallTickets
SpinLock(bool enableThreadOwnerTracking)
Initializes a new instance of the System.Threading.SpinLock struct.
void Enter(ref bool lockTaken)
void Exit(bool useMemoryBarrier)
void TryEnter(int millisecondsTimeout, ref bool lockTaken)
void TryEnter(ref bool lockTaken)