/// <summary> /// Acquires a reader lock. /// </summary> /// <returns>An object (considered opaque by client code) that should be disposed /// once the lock is not needed.</returns> /// <remarks>It is strongly recommended to use the <b>using</b> construct with /// this method.</remarks> public Cookie AcquireReadLock() { if (this.@lock == null) { return(new Cookie(CookieAction.None, null, null)); } CookieAction action; if ([email protected] && [email protected] && [email protected]) { action = CookieAction.ExitReadLock; DeadlockMonitor.EnterWaiting(@lock, writeLock, lockedObject); if ([email protected](WarningTimeout)) { Debug.Print("Acquiring a read lock on {0} from thread {1} ({2}) is taking longer than expected.", lockedObject, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.Name); DeadlockMonitor.DetectDeadlocks(); @lock.EnterReadLock(); } DeadlockMonitor.ExitWaiting(@lock, writeLock); DeadlockMonitor.EnterAcquired(@lock, readLock, lockedObject); } else { action = CookieAction.None; } return(new Cookie(action, this, GetStackTrace())); }
/// <inheritdoc /> public void Dispose() { switch (this.action) { case CookieAction.None: break; case CookieAction.ExitReadLock: [email protected](); DeadlockMonitor.ExitAcquired(this.parent.@lock, readLock); break; case CookieAction.ExitWriteLock: [email protected](); DeadlockMonitor.ExitAcquired(this.parent.@lock, writeLock); break; case CookieAction.ExitWriteAndUpgradeableReadLock: [email protected](); [email protected](); DeadlockMonitor.ExitAcquired(this.parent.@lock, writeLock); DeadlockMonitor.ExitAcquired(this.parent.@lock, upgradableReadLock); break; case CookieAction.EnterWriteLock: DeadlockMonitor.EnterWaiting(this.parent.@lock, readLock, this.parent.lockedObject); DeadlockMonitor.EnterWaiting(this.parent.@lock, writeLock, this.parent.lockedObject); DeadlockMonitor.EnterWaiting(this.parent.@lock, upgradableReadLock, this.parent.lockedObject); if ([email protected](WarningTimeout)) { Debug.Print("Reacquiring a write lock on {0} from thread {1} ({2}) is taking longer than expected.", this.parent.lockedObject, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.Name); DeadlockMonitor.DetectDeadlocks(); [email protected](); } DeadlockMonitor.ConvertWaitingToAcquired(this.parent.@lock, writeLock, this.parent.lockedObject); DeadlockMonitor.ExitWaiting(this.parent.@lock, readLock); DeadlockMonitor.ExitWaiting(this.parent.@lock, upgradableReadLock); break; case CookieAction.ExitUpgrableReaderLock: [email protected](); DeadlockMonitor.ExitAcquired(this.parent.@lock, upgradableReadLock); break; } this.action = CookieAction.None; GC.SuppressFinalize(this); }
/// <summary> /// Handler executed before execution of the method to which the current custom attribute is applied. /// </summary> /// <param name="eventArgs"></param> public override void OnEntry(MethodExecutionArgs eventArgs) { object o = eventArgs.Instance ?? eventArgs.Method.DeclaringType; DeadlockMonitor.EnterWaiting(o, null, null); if (!Monitor.TryEnter(o, 200)) { DeadlockMonitor.DetectDeadlocks(); Monitor.Enter(o); } DeadlockMonitor.ConvertWaitingToAcquired(o, null, null); }
private static void DetectProblems(int i) { if (i % DeadlockDetectionPeriod / WarningTimeout == 0) { DeadlockMonitor.DetectDeadlocks(); } // Doing a GC will collect eventual ghost locks. if (i % GarbageCollectionDetectionPeriod / WarningTimeout == 0) { GC.Collect(); } }
/// <summary> /// Acquires an observer lock. /// </summary> /// <returns>An object (considered opaque by client code) that should be disposed /// once the lock is not needed.</returns> /// <remarks>It is strongly recommended to use the <b>using</b> construct with /// this method.</remarks> public Cookie AcquireObserverLock() { if (this.@lock == null) { return(new Cookie(CookieAction.None, null, null)); } if ([email protected]) { [email protected](); DeadlockMonitor.ExitAcquired(this.@lock, writeLock); return(new Cookie(CookieAction.EnterWriteLock, this, GetStackTrace())); } else { return(new Cookie(CookieAction.None, this, GetStackTrace())); } }
/// <summary> /// Acquires an upgradable reader lock. /// </summary> /// <returns>An object (considered opaque by client code) that should be disposed /// once the lock is not needed.</returns> /// <remarks>It is strongly recommended to use the <b>using</b> construct with /// this method.</remarks> public Cookie AcquireUpgradableReadLock() { if (this.@lock == null) { return(new Cookie(CookieAction.None, null, null)); } CookieAction action; if ([email protected] && [email protected]) { if (@lock.IsReadLockHeld) { throw new InvalidOperationException( string.Format("Cannot acquire a write lock on {{{0}}}, because the current thread " + "already holds a read lock on that object, and acquiring a write lock may cause a deadlock.", @lock)); } action = CookieAction.ExitUpgrableReaderLock; DeadlockMonitor.EnterWaiting(@lock, upgradableReadLock, lockedObject); DeadlockMonitor.EnterWaiting(@lock, writeLock, lockedObject); if ([email protected](WarningTimeout)) { Debug.Print("Acquiring a read lock on {0} from thread {1} ({2}) is taking longer than expected.", lockedObject, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.Name); DeadlockMonitor.DetectDeadlocks(); @lock.EnterUpgradeableReadLock(); } DeadlockMonitor.ConvertWaitingToAcquired(@lock, upgradableReadLock, lockedObject); DeadlockMonitor.ExitWaiting(@lock, writeLock); } else { action = CookieAction.None; } return(new Cookie(action, this, GetStackTrace())); }