当 Visual Studio 中仅显示一个线程时,如何调试死锁?
我的应用程序在调用 lock ( obj )
时无限期阻塞,但线程窗口中没有其他线程有任何代码可供浏览。是否有必要涉及另一个线程?为什么不显示,不显示的原因可能是什么?
更新:我想我已经弄清楚是什么原因造成的了。我有这种黑客块,我可以在两个锁内的 ManualResetEvent
上 Wait()
。问题是我需要在等待之前释放这些锁,以便其他线程可以使用它们,所以我做了这样的事情:
lock ( one ) {
lock ( two ) {
...
Monitor.Exit( two );
Monitor.Exit( one );
syncEvent.Wait();
Monitor.Enter( one );
Monitor.Enter( two );
}
}
我没有指望的是 Monitor.Exit()
实际上只会递减内部递归计数器,并且该方法可能是从已经同步的块中调用的;因此锁实际上并未被释放。
我想这从一开始就是一个坏主意。此后,我刚刚将对 Wait()
的调用移至锁定块之外,现在似乎工作正常。
感谢您的见解。
尽管如此,现在我想一想,如果该方法是从其中一个锁上的同步代码调用的,那么当发生对 Wait
的调用时,它仍然不会被释放。因此,我想我必须小心,永远不要从同步块中调用它。
My application is blocking indefinitely on a call to lock ( obj )
, but there are no other threads in the threads window that have any code to browse at all. Isn't it kind of necessary for there to be another thread involved? Why isn't it showing up, and what could be the cause of it not showing up?
Update: I think I figured out what was causing it. I had this sort of hackish block whereby I would Wait()
on a ManualResetEvent
inside two locks. The problem was I needed to release those locks before Waiting so other threads could use them, so I was doing something like this:
lock ( one ) {
lock ( two ) {
...
Monitor.Exit( two );
Monitor.Exit( one );
syncEvent.Wait();
Monitor.Enter( one );
Monitor.Enter( two );
}
}
What I wasn't counting on is that Monitor.Exit()
really only decrements an internal recursion counter, and it was possible the method was being called from a block that was already synchronized; thus the lock was not actually being released.
I guess it was a bad idea to begin with. I've since just moved the call to Wait()
outside of the locked blocks and it seems to be working fine now.
Thanks for the insight.
Although, now that I think about it, if the method is being called from code synchronized on one of the locks, it will still not be released when the call to Wait
occurs. Therefore I'll have to be careful never to call this from a synchronized block, I guess.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我向您保证这些其他线程正在运行代码。无论您的计算机上是否有源代码,对于这些线程来说都无关紧要。
是的。
也许取出锁的线程已经进入睡眠状态。拿了锁然后在不解锁的情况下睡觉是不礼貌的,但当然是可能的。或者可能是那些正在运行代码的线程之一,您没有源代码来获取锁。例如,假设终结器线程在终结对象时取出了锁,然后终结器线程完成了当前批次的工作。同样,在终结期间锁定对象然后不解锁它是粗鲁和愚蠢的,但这当然是可能的。
有一百万种可能性;你没有给我们足够的信息,除了随机猜测之外,我们无法做任何事情。我的建议:构建一个小的重现来清楚地展示问题。这样做时,您要么自己找出问题所在,要么获得我们可以讨论的具体内容,而不是简单地在事实发生之前进行猜测。
I assure you that those other threads are running code. Whether you have the source code on your machine or not doesn't matter to those threads.
Yes.
Perhaps the thread that took out a lock has gone to sleep. It's rude to take a lock and then sleep without unlocking it, but certainly possible. Or perhaps one of those threads that is running code that you don't have the source code to took out a lock. For example, suppose the finalizer thread took out a lock while finalizing an object, and then the finalizer thread finished its current batch of work. Again, it is rude and stupid to lock an object during finalization and then not unlock it, but it is certainly possible.
There are a million possibilities; you haven't given us nearly enough information to do anything more than guess randomly. My advice: build a small repro that clearly demonstrates the problem. In doing so you'll either figure out what the problem is yourself, or you'll have something concrete that we can discuss rather than simply making guesses in advance of facts.
调试此问题的一个好方法是通过 Visual Studio 2010 中的并发分析器运行程序。(不过,这仅在高端 SKU 中可用。)它包含许多用于突出显示和调查死锁的工具,并且往往在以下环境中工作得更好:比调试器的场景更多。
A good way to debug this is to run your program through the Concurrency Profiler in Visual Studio 2010. (This is only available in higher-end SKUs, however.) It includes many tools for highlighting and investigating deadlocks, and tends to work better in many scenarios than the debugger.