代码之家  ›  专栏  ›  技术社区  ›  Jürgen Steinblock

如何找出线程锁发生在哪里?

  •  7
  • Jürgen Steinblock  · 技术社区  · 14 年前

    我们公司的一个Windows窗体应用程序几个月来出现了一个奇怪的问题。 这个应用程序对我们的大多数客户来说非常可靠,但在某些PC机上(主要是通过无线局域网连接),这个应用程序有时不再响应。(单击用户界面,Windows要求您等待或终止应用程序)。

    我很长一段时间都找不到这个问题,但现在我知道发生了什么。 应用程序有这行代码

    // don't blame me for this. Wasn't my code :D
    Control.CheckForIllegalCrossThreadCalls = false
    

    并使用一些后台线程来修改控件。

    不,我找到了一种在我的开发人员机器上重现应用程序停止响应bug的方法,并跟踪到一行,在那里我实际使用invoke()在主线程中运行任务。

    Me.Invoke(MyDelegate, arg1, arg2)
    

    显然在某个地方有一个线程锁。 在移除

    Control.CheckForIllegalCrossThreadCalls = false
    

    语句并将整个程序重构为使用invoke()。如果从后台线程修改控件,则问题(希望)会消失。

    但是,我想知道是否有一种方法可以在不调试每一行代码的情况下找到此类错误(即使在应用程序停止响应后闯入调试器,我也无法判断最后发生了什么,因为IDE没有跳转到invoke()语句)

    换言之:

    如果我的应用程序挂起,我怎么能知道 执行了哪一行代码 最后?

    甚至在客户电脑上。

    我知道VS2010提供了一些向后调试功能,也许这是一个解决方案,但目前我正在使用VS2008。

    3 回复  |  直到 14 年前
        1
  •  1
  •   Hans Passant    14 年前

    您很可能正确地识别了罪犯,将checkForIllegalCrossThreadCalls设置为false是创建随机死锁的好方法。该属性甚至存在的唯一原因是允许调试Borked.NET 1.x程序。

    要解决死锁问题,您需要使用debug+windows+线程窗口在各个线程之间切换并查看它们的调用堆栈。但考虑到源的可能性质,这将是困难的,因为很可能是非托管代码对消息队列或sendmessage()执行某些操作。您没有编写的代码,也没有源代码,也没有调试符号。它们也往往是随机的,下次它死锁时可能看起来完全不同。

    Windows基本上是线程不安全的对象。它们有大量与之相关的状态。不仅在Windows窗体类包装器中,在Windows本身中也是如此。我相信你解决了这个问题。

        2
  •  2
  •   Kiril    14 年前

    也许这可以帮助您: http://www.debuginspector.com/index.htm

    它是一个Visual Studio扩展,允许您跟踪死锁,它还有一系列用于调试线程的漂亮功能(例如,在不进入线程窗口的情况下查看多个线程的调用堆栈)。