public bool SetOwner(ThreadNode thread)
        {
            if (Owner != thread)
            {
                Interlocked.Exchange(ref refCounter, 1);
                Owner = thread;
                return(true);
            }

            Interlocked.Increment(ref refCounter);
            return(false);
        }
        private static ThreadNode GetThreadNode(Thread thread)
        {
            lock (_WaitGraphLock)
            {
                ThreadNode node;
                if (!_ThreadNodes.TryGetValue(thread.ManagedThreadId, out node))
                {
                    node = new ThreadNode(thread);
                    _ThreadNodes.Add(thread.ManagedThreadId, node);
                }

                return(node);
            }
        }
        public bool RemoveOwner(ThreadNode thread)
        {
            if (Owner != thread)
            {
                return(true);
            }

            if (Interlocked.Decrement(ref refCounter) <= 0)
            {
                Owner = null;
                return(true);
            }

            return(false);
        }
        private static WaitGraphCycle FindCycle(ThreadNode thread)
        {
            var threads = new HashSet <ThreadNode>();

            while (true)
            {
                // Если поток не ожидает лока, то он не может быть частью цикла
                if (thread.WaitsForLockObject == null)
                {
                    return(null);
                }

                // Если поток ожидает лока, коим уже владеет, он не может быть частью цикла,
                // ибо это случай рекурсивной блокировки
                if (thread.WaitsForLockObject.Owner == thread)
                {
                    return(null);
                }

                // Если поток уже обрабатывался, то это цикл
                if (threads.Contains(thread))
                {
                    // Обнаружен цикл
                    return(new WaitGraphCycle(
                               threads.ToArray(),
                               threads.Select(_ => _.WaitsForLockObject).ToArray()
                               ));
                }

                // Объект thread.WaitsForLockObject никем не занят, дедлока нет
                if (thread.WaitsForLockObject.Owner == null)
                {
                    return(null);
                }

                // Добавляем поток в стек
                threads.Add(thread);

                // Идем дальше
                thread = thread.WaitsForLockObject.Owner;
            }
        }
        private static void AppendStackTrace(ThreadNode threadNode, StringBuilder message)
        {
#if NETSTANDARD1_6
            message.AppendLine("(not available)");
#elif NET45 || NET46
            string stackTraceString = null;
            var    needResume       = false;
            try
            {
                if (threadNode.Thread != Thread.CurrentThread)
                {
#pragma warning disable 612, 618
                    threadNode.Thread.Suspend();
#pragma warning restore 612, 618
                    needResume = true;
                }
#pragma warning disable 612, 618
                var stackTrace = new StackTrace(threadNode.Thread, false);
#pragma warning restore 612, 618
                stackTraceString = stackTrace.ToString();
            }
            catch
            {
                if (stackTraceString == null)
                {
                    stackTraceString = "(not available)";
                }
            }
            finally
            {
                if (needResume)
                {
#pragma warning disable 612, 618
                    threadNode.Thread.Resume();
#pragma warning restore 612, 618
                }
            }

            message.AppendLine(stackTraceString);
#endif
        }
        private static void AppendThreadState(ThreadNode threadNode, StringBuilder message, bool enableStackTrace)
        {
            message.AppendFormat("[Thread {0}] {1:G}\r\n", threadNode.Name, threadNode.Thread.ThreadState);

            if (threadNode.WaitsForLockObject != null)
            {
                message.AppendFormat("Waits for lock {0}\r\n", threadNode.WaitsForLockObject.Name);
            }
            else
            {
                message.AppendFormat("Doesn't wait for any lock\r\n");
            }

            message.AppendFormat(
                "Owned locks: [ {0} ]\r\n",
                string.Join(", ", threadNode.GetOwnedLocks().Select(_ => _.Name)));
            if (enableStackTrace)
            {
                message.AppendLine("Stack trace:");
                AppendStackTrace(threadNode, message);
            }
            message.AppendLine("------------");
        }
        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));
        }
 public void RemoveWaitingThread(ThreadNode thread)
 {
     thread.WaitsForLockObject = null;
     waitingThreads.Remove(thread);
 }
 public void RegisterWaitingThread(ThreadNode thread)
 {
     thread.WaitsForLockObject = this;
     waitingThreads.Add(thread);
 }
Example #10
0
 private bool Equals(ThreadNode other)
 {
     return(thread.Equals(other.thread));
 }