Using .NET reflector, I find that the SpinLock structure has a lot of cases where it calls Thread.BeginCriticalRegion and doesn't call Thread.EndCriticalRegion. For example, in the public function SpinLock.Enter(ref bool lockTaken) (.NET 4.0):
// ...
Thread.BeginCriticalRegion();
if (Interlocked.CompareExchange(ref this.m_owner, managedThreadId, owner, ref lockTaken) == owner)
return; // <--- !!
Thread.EndCriticalRegion();
// ...
In another case, SpinLock.Exit seems to call Thread.EndCriticalRegion without having called Thread.BeginCriticalRegion.
public void Exit(bool useMemoryBarrier)
{
if (this.IsThreadOwnerTrackingEnabled && !this.IsHeldByCurrentThread)
throw ...
if (useMemoryBarrier)
{
if (this.IsThreadOwnerTrackingEnabled)
Interlocked.Exchange(ref this.m_owner, 0);
else
Interlocked.Decrement(ref this.m_owner);
}
else if (this.IsThreadOwnerTrackingEnabled)
this.m_owner = 0;
else
{
int owner = this.m_owner;
this.m_owner = owner - 1;
}
Thread.EndCriticalRegion(); // <--- ??
}
开发者_运维百科So the question: do any problems ensue from not balancing calls to Begin/EndCriticalRegion?
Note that the Begin/End calls do balance if the lock is actually taken and then released by calling Exit(). The calls to mark the critical region are necessary to let the CLR know that thread interruptions may be damaging while a SpinLock is acquired. See here for more info.
精彩评论