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); }
private bool Equals(ThreadNode other) { return(thread.Equals(other.thread)); }