.NETリフレクターを使用すると、SpinLock構造体がThread.BeginCriticalRegionを呼び出し、Thread.EndCriticalRegionを呼び出さない場合が多いことがわかりました。たとえば、パブリック関数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();
// ...
別のケースでは、SpinLock.ExitはThread.BeginCriticalRegionを呼び出さずにThread.EndCriticalRegionを呼び出しているようです。
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(); // <--- ??
}
したがって、質問:Begin / EndCriticalRegionへの呼び出しのバランスをとらないことで問題が発生しますか?