// // Taking the Upgradable read lock is like taking a read lock // but we limit it to a single upgradable at a time. // public bool TryEnterUpgradeableReadLock(int millisecondsTimeout) { ThreadLockState ctstate = CurrentThreadState; if (CheckState(ctstate, millisecondsTimeout, LockState.Upgradable)) { ++ctstate.UpgradeableRecursiveCount; return(true); } if (ctstate.LockState.Has(LockState.Read)) { throw new LockRecursionException("The current thread has already entered read mode"); } ++numUpgradeWaiters; long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds; // We first try to obtain the upgradeable right while (!upgradableEvent.IsSet() || !upgradableTaken.TryRelaxedSet()) { if (millisecondsTimeout != -1 && (sw.ElapsedMilliseconds - start) > millisecondsTimeout) { --numUpgradeWaiters; return(false); } upgradableEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); } upgradableEvent.Reset(); // Then it's a simple reader lock acquiring if (TryEnterReadLock(ComputeTimeout(millisecondsTimeout, start))) { ctstate.LockState = LockState.Upgradable; --numUpgradeWaiters; --ctstate.ReaderRecursiveCount; ++ctstate.UpgradeableRecursiveCount; return(true); } upgradableTaken.Value = false; upgradableEvent.Set(); --numUpgradeWaiters; return(false); }
// // Taking the Upgradable read lock is like taking a read lock // but we limit it to a single upgradable at a time. // public bool TryEnterUpgradeableReadLock(int millisecondsTimeout) { var currentThreadState = CurrentThreadState; if (CheckState(currentThreadState, millisecondsTimeout, LockState.Upgradable)) { ++currentThreadState.UpgradeableRecursiveCount; return(true); } if (currentThreadState.LockState.Has(LockState.Read)) { throw new LockRecursionException("The current thread has already entered read mode"); } ++WaitingUpgradeCount; var start = millisecondsTimeout == -1 ? 0 : _stopwatch.ElapsedMilliseconds; var taken = false; var success = false; // We first try to obtain the upgradeable right try { while (!_upgradableEvent.IsSet() || !taken) { try { } finally { taken = _upgradableTaken.TryRelaxedSet(); } if (taken) { break; } if (millisecondsTimeout != -1 && _stopwatch.ElapsedMilliseconds - start > millisecondsTimeout) { --WaitingUpgradeCount; return(false); } _upgradableEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); } _upgradableEvent.Reset(); RuntimeHelpers.PrepareConstrainedRegions(); try { // Then it's a simple reader lock acquiring TryEnterReadLock(ComputeTimeout(millisecondsTimeout, start), ref success); } finally { if (success) { currentThreadState.LockState |= LockState.Upgradable; currentThreadState.LockState &= ~LockState.Read; --currentThreadState.ReaderRecursiveCount; ++currentThreadState.UpgradeableRecursiveCount; } else { _upgradableTaken.Value = false; _upgradableEvent.Set(); } } --WaitingUpgradeCount; } catch (Exception ex) { GC.KeepAlive(ex); // An async exception occured, if we had taken the upgradable mode, release it _upgradableTaken.Value &= !taken || success; } return(success); }
// // Taking the Upgradable read lock is like taking a read lock // but we limit it to a single upgradable at a time. // public bool TryEnterUpgradeableReadLock(int millisecondsTimeout) { ThreadLockState ctstate = CurrentThreadState; if (CheckState(ctstate, millisecondsTimeout, LockState.Upgradable)) { ++ctstate.UpgradeableRecursiveCount; return(true); } if (ctstate.LockState.Has(LockState.Read)) { throw new LockRecursionException("The current thread has already entered read mode"); } ++numUpgradeWaiters; long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds; bool taken = false; bool success = false; // We first try to obtain the upgradeable right try { while (!upgradableEvent.IsSet() || !taken) { try {} finally { taken = upgradableTaken.TryRelaxedSet(); } if (taken) { break; } if (millisecondsTimeout != -1 && (sw.ElapsedMilliseconds - start) > millisecondsTimeout) { --numUpgradeWaiters; return(false); } upgradableEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); } upgradableEvent.Reset(); RuntimeHelpers.PrepareConstrainedRegions(); try { // Then it's a simple reader lock acquiring TryEnterReadLock(ComputeTimeout(millisecondsTimeout, start), ref success); } finally { if (success) { ctstate.LockState |= LockState.Upgradable; ctstate.LockState &= ~LockState.Read; --ctstate.ReaderRecursiveCount; ++ctstate.UpgradeableRecursiveCount; } else { upgradableTaken.Value = false; upgradableEvent.Set(); } } --numUpgradeWaiters; } catch { // An async exception occured, if we had taken the upgradable mode, release it if (taken && !success) { upgradableTaken.Value = false; } } return(success); }