【问题标题】:How to handle third party functions or threads that has hung in Delphi?如何处理在 Delphi 中挂起的第三方函数或线程?
【发布时间】:2012-08-15 16:26:32
【问题描述】:

我在我的 Delphi 7 Service 应用程序、Indy、Synapse、Zeolibs 等中使用了很多组件。

我的应用程序总体上是稳定的,我使用 Eurekalog 6 来捕获异常,但在极少数情况下,一些线程挂起,因为它调用的第 3 方函数挂起,例如Indy 在尝试发送电子邮件时卡住了。

在许多情况下,挂起的应用程序是我的客户所在的位置,我无法访问他们的计算机,因此我无法进行实时调试。我的应用程序需要高可用性,因此即使每年挂起一次,我的用户也无法接受。

我现在正在寻找最好的方法来处理这种调试不可行但我仍然需要应用程序自行恢复的情况。如果线程调用的函数挂起,线程是否可以终止?或者,我也可以在发生这种情况时重新启动整个服务。看门狗怎么样?实现它的最佳方法是什么?谢谢。

【问题讨论】:

  • 看看 madshi 的madExcept。它将允许您的应用程序或您的用户发送整个堆栈跟踪并检测挂起的主线程。任何其他挂起的线程,您应该可以编写代码。
  • @LURD 在线程中处理异常有什么特别之处?任何线程、主线程或工作线程中的异常处理肯定都是相同的吗?
  • @DavidHeffernan,线程执行中未处理的异常很难发现。您必须在线程被释放之前检查线程属性FatalException 以获取异常。
  • @LURD 好吧,我总是将我的线程过程包装在一个 try/except 中,我猜这会是同样的事情。

标签: delphi delphi-7


【解决方案1】:

我认为你是相当失败主义者。查找并修复错误。这可能很棘手,但它是正确的解决方案。

杀死你不理解行为的线程永远不是解决方案。如果你开始杀死线程,你可能会让事情变得更糟。这可能导致其他运行时错误、死锁等。一旦你开始杀死线程,你就失去了控制。

现在,杀死进程(而不是特定线程)并依靠看门狗服务重新启动进程是安全的。但这是一个非常糟糕的解决方案。

您当然应该使用 madExcept、EurekaLog 等工具来调试意外异常。我看到你已经在使用 EurekaLog - 这很好。

死锁(听起来你有死锁)可能更难追上。调试死锁的一种好方法是让您的客户端生成故障转储(例如,来自 Process Explorer)。然后在 WinDbg 中使用 map2dbg 对其进行调试以生成符号堆栈跟踪。这将告诉您哪些线程正在阻塞并揭示死锁。然后修复错误。

有关此死锁调试技术的更多详细信息,请参见此处:http://capnbry.net/blog/?p=18

我不熟悉 EurekaLog,因为我使用了 madExcept,但我希望 EurekaLog 有一个工具可以为挂起的进程生成线程堆栈跟踪。如果是这样,那么这很可能是最适合您的方法。

【讨论】:

  • 杀死线程肯定是解决方法而不是解决方案。然而,这种解决方法并不是那么毫无意义。如果 3rd 方库导致冻结,那么在其中找到错误而没有机会调试是相当棘手的。如果他的数据结构完全是线程本地的并且是隔离的,那么杀死线程并不是很危险。相反,根据“在存在软件错误的情况下构建可靠的分布式系统”,有时杀死并重试是一种解决方案。有时不是。那么他将在应用程序重新启动之前出现级联故障。
  • @arioch 如果要杀死的线程是完全隔离的,那么除了堆内存泄漏之外它是安全的。但无论如何,最有可能的错误都在 OP 的代码中。如果不调试库也不难。这些库带有源代码。
  • @David Heffernan - 你说得对,我说的是死锁。它们不经常发生,但我的应用程序有时用于关键任务场景。 Eurekalog 已经可以捕获所有未处理的异常,但也有没有异常但应用被锁定的情况。我现在正在探索如何最好地实现看门狗,因此如果任何线程挂起,看门狗将重新启动该进程。为了您的信息,我已经在服务中使用了一个看门狗计时器来重置我创建的外部看门狗服务,但这不适用于挂起线程 - 它只有在计时器(整个服务)挂起时才有效。
【解决方案2】:

你的问题太模糊了。如果您不知道要归咎于您正在使用的各种组件中的哪一个,那么您修复它的希望为零。最有可能的是您做错了什么,或者您不了解这些组件的工作原理。我非常怀疑这纯粹是组件本身的错误,但是,嘿,无论哪种方式,都取决于您找出问题所在,并解决问题。

您创建的死锁或正在发生的深层进程损坏问题可能会阻止 MadExcept 向您提供任何信息,但值得一试。

要找出哪个是冻结的,如果有的话,那么 madexcept 评论是最好的建议。它将超时(在可配置的秒数之后)并为您引发人为异常,从而中断您挂起的过程。这适用于用户代码,以及线程在 Win32 或内核函数中被阻塞的地方。例如,您可能已将 Indy 设置为无限超时,因为这是 Indy 10 中这些天的默认设置,并且您遇到的是与超时相关的冻结,您希望完成但从未完成的网络活动将完成,导致您的程序“挂起”。解决方法是更改​​您的超时时间。

但是,在您弄清楚问题出在哪里之前,我怀疑您是否能够解决它。所以,为此,Marcus 是对的,你应该调查 madExcept。没有它我活不下去。

其次,您应该真正为您的程序添加跟踪逻辑,这样您就知道它的去向以及在它出现问题之前它在做什么。如果你真的需要帮助,你可以试试 Raize 的 CodeSite。我个人发现 OutputDebugString 与免费的 Microsoft DebugView 实用程序(以前来自 SysInternals)工具相结合,足以在客户端计算机上调试此类问题。

任何具有后台线程但没有跟踪日志记录的程序都是设计不佳的程序。哎呀,任何可能失败或有问题的重要单线程应用程序都需要跟踪日志记录。

即使 MadExcept 或其他异常工具没有帮助,日志记录也总是会有所帮助。尽管 CodeSite 也很受欢迎,但 Trace-Logging 通常是一个自己动手的解决方案。

【讨论】:

  • 我非常同意 CodeSite 和 SmartInspect 是一流的调试工具。如果 OP 在调试时遇到很多麻烦,我建议使用这些工具之一。我使用 SmartInspect,但两者都是同样出色的 IHMO。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
相关资源
最近更新 更多