识别持有锁的线程

我的应用程序中的一个线程在以下锁定语句中被阻塞并导致死锁

void ExecuteCommand() { lock(this._lockinstance) { // do some operation } } 

是否有可能轻松识别当前持有锁的哪个线程?..我的应用程序有超过50个线程,这使得使用visual studio难以通过每个callstack来定位持有锁的线程

尝试一些示例代码:

 class Test { private object locker = new object(); public void Run() { lock (locker) { // <== breakpoint here Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); } } } 

在指示的行上设置断点。 当它中断时,使用Debug + Windows + Memory + Memory 1.右键单击窗口并选择“4-byte Integer”。 在“地址”框中,键入&locker。 第二个字是拥有锁的线程的线程ID。 跳过锁定语句以查看其更改。

请注意,该数字是托管线程ID,而不是您在Debug + Windows + Threads窗口中看到的操作系统线程ID。 这有点糟糕,您可能应该向您的程序添加一些转储ManagedThreadId值的日志记录,以便您可以将值与线程匹配。 更新:在以后的VS版本中修复,Debug> Windows> Threads调试器窗口现在显示ManagedThreadId。

您可以实现一个Monitor包装器,在输入时保存堆栈跟踪和线程名称。

旧方式:

 private object myLock = new object(); ... lock(myLock) { DoSomething(); } ... 

使用以下代码:

 private SmartLock myLock = new SmartLock(); ... myLock.Lock( () => { DoSomething(); } ); ... 

资源:

 public class SmartLock { private object LockObject = new object(); private string HoldingTrace = ""; private static int WARN_TIMEOUT_MS = 5000; //5 secs public void Lock(Action action) { try { Enter(); action.Invoke(); } catch (Exception ex) { Globals.Error("SmartLock Lock action", ex); } finally { Exit(); } } private void Enter() { try { bool locked = false; int timeoutMS = 0; while (!locked) { //keep trying to get the lock, and warn if not accessible after timeout locked = Monitor.TryEnter(LockObject, WARN_TIMEOUT_MS); if (!locked) { timeoutMS += WARN_TIMEOUT_MS; Globals.Warn("Lock held: " + (timeoutMS / 1000) + " secs by " + HoldingTrace + " requested by " + GetStackTrace()); } } //save a stack trace for the code that is holding the lock HoldingTrace = GetStackTrace(); } catch (Exception ex) { Globals.Error("SmartLock Enter", ex); } } private string GetStackTrace() { StackTrace trace = new StackTrace(); string threadID = Thread.CurrentThread.Name ?? ""; return "[" + threadID + "]" + trace.ToString().Replace('\n', '|').Replace("\r", ""); } private void Exit() { try { Monitor.Exit(LockObject); HoldingTrace = ""; } catch (Exception ex) { Globals.Error("SmartLock Exit", ex); } } } 

是的,您可以在VS中使用“线程”视图。 在应用程序中的任何位置中断(或单击“全部中断”按钮),然后您可以选择每个线程并查看谁拥有锁定(如果有人)。

要添加它,请转到Debug> Windows> Threads(Ctrl + D,T)

老post很旧。

但我想我可能会提供一个解决方案,我发现它对于尝试追踪死锁和其他锁定问题非常有用。

我为我的锁使用一次性类 – 我喜欢Monitor但可以使用任何锁定机制。

 public class MonitorLock : IDisposable { public static MonitorLock CreateLock(object value) { return new MonitorLock(value); } private readonly object _l; protected MonitorLock(object l) { _l = l; Console.WriteLine("Lock {0} attempt by {1}", _l, Thread.CurrentThread.ManagedThreadId); Monitor.Enter(_l); Console.WriteLine("Lock {0} held by {1}" , _l, Thread.CurrentThread.ManagedThreadId); } public void Dispose() { Monitor.Exit(_l); Console.WriteLine("Lock {0} released by {1}", _l, Thread.CurrentThread.ManagedThreadId); } } 

我使用一个带有名字的锁对象,这样我就可以清楚地知道我想要获取哪个锁。

 public class LockObject { public string Name { get; set; } public LockObject(string name) { Name = name; } public override string ToString() { return Name; } } 

最后创建一个锁对象,然后在一个using块中保存该对象。

 //create an object to lock on private readonly object _requestLock = new LockObject("_requestLock"); using (MonitorLock.CreateLock(_requestLock)) { //do some work } 

输出应该是符合的

 Lock _requestLock attempt by 92 Lock _requestLock held by 92 Lock _requestLock attempt by 19 Lock _requestLock released by 92 Lock _requestLock held by 19 Lock _requestLock released by 19 

希望有人发现这个有用:)

最近我试图确定哪个函数持有一个锁,并发现以下非常有用,并且之前在任何地方都没有看过。 我把它放在这里作为答案,以防其他人发现它也有用。

之前发布的许多其他解决方案都需要编写一个新类,然后将所有锁(blah)转换为BetterLock(blah),这是调试的大量工作,您可能不需要在生产/发布的代码版本中。 其他人需要附加调试器,这会改变代码的时序并且可能会使问题变得模糊。

相反,尝试以下……

原始代码:

 object obj = new object(); lock(obj) { // Do stuff } 

修改后的调试代码:

 object _obj = new object(); object obj { get { System.Diagnostics.StackFrame frame = new System.Diagnostics.StackFrame(1); System.Diagnostics.Trace.WriteLine(String.Format("Lock acquired by: {0} on thread {1}", frame.GetMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId)); return _obj; } } // Note that the code within lock(obj) and the lock itself remain unchanged. lock(obj) { // Do stuff } 

通过将obj作为属性公开,至少是暂时的,只需极少的代码更改,您可以确定最后获取锁的函数以及在哪个线程上获取 – 只需查看最后一个条目的Trace输出。 当然,您也可以输出您在getter中可能会发现的任何其他信息。

不,这不会让你确定锁何时被释放,但是如果它及时释放,那么你实际上并没有首先遇到锁争用问题。

来自http://mse.codeplex.com/或http://www.microsoft.com/downloadS/details.aspx?FamilyID=80cf81f7-d710-47e3-8b95-5a6555a230c2&displaylang=en的Managed Stack Explorer在这种情况下非常出色。

它挂钩运行托管代码(需要适当的权限),包括实时代码,并抓取正在运行的线程列表。 您可以双击其中任何一个或(在这种情况下更有用)选择批次并按Enter键以快速相对非侵入性(显然它将消耗资源,但它会尽可能快地进出) )转储当前不同线程的堆栈。 非常适合找到死锁,无限循环,近无限循环(对于那些当你的应用意外地依赖于天文学家对地球将持续多久有希望完成的悲观情绪时)以及其他此类情况。