.NET SpinLock не освобождает поток.BeginCriticalSection

#.net #spinlock

#.net #блокировка вращения

Вопрос:

Использование .ЧИСТЫЙ рефлектор, я обнаружил, что в структуре SpinLock много случаев, когда она вызывает поток.BeginCriticalRegion и не вызывает поток.EndCriticalRegion. Например, в общедоступной функции SpinLock.Введите (блокировка ref bool заблокирована) (.NET 4.0):

 // ...
Thread.BeginCriticalRegion();
if (Interlocked.CompareExchange(ref this.m_owner, managedThreadId, owner, ref lockTaken) == owner)
    return;  // <--- !!
Thread.EndCriticalRegion();
// ...
  

В другом случае происходит блокировка вращения.Выход, похоже, вызывает поток.EndCriticalRegion без вызова потока.BeginCriticalRegion.

 public void Exit(bool useMemoryBarrier)
{
    if (this.IsThreadOwnerTrackingEnabled amp;amp; !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?

Ответ №1:

Обратите внимание, что вызовы Begin / End выполняют балансировку, если блокировка действительно снята, а затем снята вызовом Exit(). Вызовы для обозначения критической области необходимы, чтобы сообщить среде CLR, что прерывания потока могут нанести ущерб при получении блокировки вращения. Смотрите здесь для получения дополнительной информации.

Комментарии:

1. Спасибо за эту информацию; Я не подумал об этом, потому что инстинктивно предположил, что CriticalRegion не должен храниться над непредсказуемым внешним кодом.