public void ExitWriteLock() { try {} finally { ThreadLockState ctstate = CurrentThreadState; if (!ctstate.LockState.Has(LockState.Write)) { throw new SynchronizationLockException("The current thread has not entered the lock in write mode"); } if (--ctstate.WriterRecursiveCount == 0) { bool isUpgradable = ctstate.LockState.Has(LockState.Upgradable); ctstate.LockState ^= LockState.Write; int value = Interlocked.Add(ref rwlock, isUpgradable ? RwRead - RwWrite : -RwWrite); writerDoneEvent.Set(); if (isUpgradable && value >> RwReadBit == 1) { readerDoneEvent.Reset(); } } } }
bool CheckState(ThreadLockState state, int millisecondsTimeout, LockState validState) { if (disposed) { throw new ObjectDisposedException("ReaderWriterLockSlim"); } if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } // Detect and prevent recursion LockState ctstate = state.LockState; if (ctstate != LockState.None && noRecursion && (!ctstate.Has(LockState.Upgradable) || validState == LockState.Upgradable)) { throw new LockRecursionException("The current thread has already a lock and recursion isn't supported"); } if (noRecursion) { return(false); } // If we already had right lock state, just return if (ctstate.Has(validState)) { return(true); } CheckRecursionAuthorization(ctstate, validState); return(false); }
public void ExitReadLock() { try {} finally { ThreadLockState ctstate = CurrentThreadState; if (!ctstate.LockState.Has(LockState.Read)) { throw new SynchronizationLockException("The current thread has not entered the lock in read mode"); } if (--ctstate.ReaderRecursiveCount == 0) { ctstate.LockState ^= LockState.Read; if (Interlocked.Add(ref rwlock, -RwRead) >> RwReadBit == 0) { readerDoneEvent.Set(); } } } }
public void ExitUpgradeableReadLock() { try {} finally { ThreadLockState ctstate = CurrentThreadState; if (!ctstate.LockState.Has(LockState.Upgradable | LockState.Read)) { throw new SynchronizationLockException("The current thread has not entered the lock in upgradable mode"); } if (--ctstate.UpgradeableRecursiveCount == 0) { upgradableTaken.Value = false; upgradableEvent.Set(); ctstate.LockState &= ~LockState.Upgradable; if (Interlocked.Add(ref rwlock, -RwRead) >> RwReadBit == 0) { readerDoneEvent.Set(); } } } }
// // 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(); 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); }
public bool TryEnterWriteLock(int millisecondsTimeout) { ThreadLockState ctstate = CurrentThreadState; if (CheckState(ctstate, millisecondsTimeout, LockState.Write)) { ++ctstate.WriterRecursiveCount; return(true); } ++numWriteWaiters; bool isUpgradable = ctstate.LockState.Has(LockState.Upgradable); bool registered = false; bool success = false; try { /* If the code goes there that means we had a read lock beforehand * that need to be suppressed, we also take the opportunity to register * our interest in the write lock to avoid other write wannabe process * coming in the middle */ if (isUpgradable && rwlock >= RwRead) { try {} finally { if (Interlocked.Add(ref rwlock, RwWaitUpgrade - RwRead) >> RwReadBit == 0) { readerDoneEvent.Set(); } registered = true; } } int stateCheck = isUpgradable ? RwWaitUpgrade + RwWait : RwWait; long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds; do { int state = rwlock; if (state <= stateCheck) { try {} finally { if (Interlocked.CompareExchange(ref rwlock, RwWrite, state) == state) { writerDoneEvent.Reset(); ctstate.LockState ^= LockState.Write; ++ctstate.WriterRecursiveCount; --numWriteWaiters; registered = false; success = true; } } if (success) { return(true); } } state = rwlock; // We register our interest in taking the Write lock (if upgradeable it's already done) if (!isUpgradable) { while ((state & RwWait) == 0) { try {} finally { if (Interlocked.CompareExchange(ref rwlock, state | RwWait, state) == state) { registered = true; } } if (registered) { break; } state = rwlock; } } // Before falling to sleep do { if (rwlock <= stateCheck) { break; } if ((rwlock & RwWrite) != 0) { writerDoneEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); } else if ((rwlock >> RwReadBit) > 0) { readerDoneEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); } } while (millisecondsTimeout < 0 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout); } while (millisecondsTimeout < 0 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout); --numWriteWaiters; } finally { if (registered) { Interlocked.Add(ref rwlock, isUpgradable ? -RwWaitUpgrade : -RwWait); } } return(false); }
public bool TryEnterReadLock(int millisecondsTimeout, ref bool success) { ThreadLockState ctstate = CurrentThreadState; if (CheckState(ctstate, millisecondsTimeout, LockState.Read)) { ++ctstate.ReaderRecursiveCount; return(true); } // This is downgrading from upgradable, no need for check since // we already have a sort-of read lock that's going to disappear // after user calls ExitUpgradeableReadLock. // Same idea when recursion is allowed and a write thread wants to // go for a Read too. if (ctstate.LockState.Has(LockState.Upgradable) || (!noRecursion && ctstate.LockState.Has(LockState.Write))) { try {} finally { Interlocked.Add(ref rwlock, RwRead); ctstate.LockState |= LockState.Read; ++ctstate.ReaderRecursiveCount; success = true; } return(true); } ++numReadWaiters; int val = 0; long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds; do { /* Check if a writer is present (RwWrite) or if there is someone waiting to * acquire a writer lock in the queue (RwWait | RwWaitUpgrade). */ if ((rwlock & (RwWrite | RwWait | RwWaitUpgrade)) > 0) { writerDoneEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); continue; } /* Optimistically try to add ourselves to the reader value * if the adding was too late and another writer came in between * we revert the operation. */ try {} finally { if (((val = Interlocked.Add(ref rwlock, RwRead)) & (RwWrite | RwWait | RwWaitUpgrade)) == 0) { /* If we are the first reader, reset the event to let other threads * sleep correctly if they try to acquire write lock */ if (val >> RwReadBit == 1) { readerDoneEvent.Reset(); } ctstate.LockState ^= LockState.Read; ++ctstate.ReaderRecursiveCount; --numReadWaiters; success = true; } else { Interlocked.Add(ref rwlock, -RwRead); } } if (success) { return(true); } writerDoneEvent.Wait(ComputeTimeout(millisecondsTimeout, start)); } while (millisecondsTimeout == -1 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout); --numReadWaiters; return(false); }