/// <summary> /// Проверить, не создает ли дедлока запрос текущим потоком блокировки <paramref name="lockObject"/> с уровнем доступа <paramref name="level"/>. /// </summary> public static void VerifyDeadlock(object lockObject, LockAccessLevel level) { lock (_WaitGraphLock) { // Пытаемся найти цикл в графе ожидания, который начинается с текущего потока // Если такой цикл существует, то имеем дедлок (произвольной глубины) var currentThread = GetThreadNode(Thread.CurrentThread); var cycle = FindCycle(currentThread); if (cycle == null) { return; } // Формируем исключение DeadlockException exception; try { var lockObjectNode = GetLockObjectNode(lockObject); exception = CreateDeadlockException(lockObjectNode, currentThread, cycle, level); } finally { // Отменяем текущую операцию ожидания var node = GetLockObjectNode(lockObject); node.RemoveWaitingThread(currentThread); } // Бросаем исключение throw exception; } }
/// <summary> /// Отменить регистрацию текущего потока как ожидающиего блокировки <paramref name="lockObject"/> с уровнем доступа <paramref name="level"/> /// </summary> public static void RemoveWaiting(object lockObject, LockAccessLevel level) { lock (_WaitGraphLock) { var node = GetLockObjectNode(lockObject); var thread = GetThreadNode(Thread.CurrentThread); node.RemoveWaitingThread(thread); } }
private static bool TryEnterLock <T>( T lockObject, LockAccessLevel level, Func <T, bool> wait) { DeadlockDetectionEngine.RegisterWaiting(lockObject, level); if (!wait(lockObject)) { DeadlockDetectionEngine.RemoveWaiting(lockObject, level); return(false); } // Помечаем данный поток как имеющий блокировку объекта obj с уровнем level DeadlockDetectionEngine.RegisterOwner(lockObject, level); return(true); }
private static void EnterLock <T>( T lockObject, LockAccessLevel level, Func <T, bool> optimisticWait, Action <T> wait) { // Сначала дожидаемся в пределах оптимистичного таймаута DeadlockDetectionEngine.RegisterWaiting(lockObject, level); if (!optimisticWait(lockObject)) { // Если блокировка не былаа захвачена в течении оптимистичного таймаута, // то проверяем, нет ли дедлока DeadlockDetectionEngine.VerifyDeadlock(lockObject, level); // Дожидаемся захвата блокировки wait(lockObject); } // Помечаем данный поток как имеющий блокировку объекта obj с уровнем level DeadlockDetectionEngine.RegisterOwner(lockObject, level); }
private static DeadlockException CreateDeadlockException( LockObjectNode lockObject, ThreadNode currentThread, WaitGraphCycle cycle, LockAccessLevel level) { var errorMessage = new StringBuilder(); errorMessage.AppendFormat( "Deadlock detected in thread {0} while trying to acquire {1} access to object \"{2}\".\r\n", currentThread.Name, level, lockObject.Name); errorMessage.Append("Wait chain: \r\n"); foreach (var obj in cycle.LockObjects) { errorMessage.AppendFormat( " * Thread {0} waits for {1} owned by thread {2}\r\n", cycle.Threads.Where(_ => _.WaitsForLockObject == obj).Select(_ => _.Name).FirstOrDefault(), obj.Name, obj.Owner.Name); } foreach (var thread in cycle.Threads) { AppendThreadState(thread, errorMessage, true); } var message = errorMessage.ToString(); DeadlockMonitor.Callback?.Invoke(message); return(new DeadlockException(message)); }