/// <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));
        }