【问题标题】:What could cause a C++Builder / Delphi thread and application to not shut down?什么可能导致 C++Builder/Delphi 线程和应用程序无法关闭?
【发布时间】:2011-06-13 13:59:03
【问题描述】:

有一次,在测试期间,我的 C++Builder / Delphi 应用程序在后台工作线程中引发了未捕获的异常。正如我所料,EurekaLog 捕获了异常并发送了错误报告,一切似乎都很好。

但是,当我关闭应用程序的主窗口时,某些东西仍在后台运行,因为该应用程序仍然列在任务管理器中(并且仍然有资源打开)。

我试图通过在后台工作线程中故意引入各种错误来复制这个问题,但我做不到。

什么会导致线程和应用程序继续这样运行,即使在主窗口关闭之后(并且可能已经调用了 PostQuitMessage)?

如何确保应用程序始终干净关闭?

【问题讨论】:

  • 您是否有任何可能无限阻塞的 EnterCriticalSection 代码?这是一个非常常见的死锁,可以在关机时解决,就在那里。

标签: windows multithreading delphi c++builder shutdown


【解决方案1】:

第一条规则是线程主执行器方法应该被编写,以便它们可以发出信号并正确关闭,第二条规则是你不应该先关闭应用程序的主线程,然后希望其他线程在自己的时间关闭,为了安全起见,您应该通知所有后台线程停止,等待关闭完成,然后关闭您的主线程。一个最小的线程示例:

procedure TMyThread.Execute;
begin
   Init;
   while not Terminated do
      OneWorkItem; // inside OneWorkItem, you  ALSO need to check for Terminated
end;

一个最小的主窗体/主线程示例:

   procedure TMyMainForm.CheckAndShutdown;
   begin
     if FPendingShutdownFlag then 
       if AllBackgroundThreadsTerminated then 
             Self.Close;
   end;

您可以设置 FPendingShutdownFlag 并从应用程序空闲处理循环中调用上述函数。当您让用户单击主窗体 FormClose 时,如果 AllBackgroundThreadsT​​erminated 返回 false,则将 CanClose 设置为 false,并改为设置 FPendingShutdownFlag := true

如果您进行无限循环(如果为真),则应用程序不会完全关闭,即使您看起来是这样。不知何故,应用程序终止了,正在运行的线程可能会突然安静地消失,或者它们可能会死锁或以其他方式失败,因为它们可能正在使用线程 2 中的资源,而您正忙于在线程 1 中释放它们。

您可能有一个或多个故意的竞争条件,因为您可能没有将线程执行方法编写为可中断的,或者您可能在确定您的应用程序线程和 VCL 及其对象之前开始关闭后台线程完全关闭。

【讨论】:

  • 我一定没有很好地解释自己。我尽我所能将我的线程编写为可中断的,检查 TThread.Terminated,避免死锁和资源问题等。不知何故,有一次,尽管如此,我的应用程序没有终止;即使它的窗体已经关闭,它仍然在后台运行。我想知道为什么以及如何预防。我做了我能想到的一切来复制那个错误状态(包括添加一个无限的 while(true) 循环),以便我弄清楚如何从中恢复,但我仍然无法复制错误状态。
  • 那么听起来您正在代码中寻找难以捉摸的竞争条件或其他类似的间歇性异步故障。您是否有任何可能长时间阻塞的 TThread.Synchronize 调用?你有任何 Sleep() 电话吗?例如,您可能会遇到我所说的“睡美人”问题。如果后台线程完全使用任何对象或声明主线程将要释放,则必须在关闭主线程之前完全关闭后台线程。
  • 在我看来,您应该首先使用大量输出调试字符串消息来检测您的代码,然后在代码失败的客户端系统上运行它,以及 MS DebugView(一个输出调试字符串查看器)并查看在客户端系统上到达或未到达的代码部分。
  • 好吧,如果后台工作线程不直接与主线程控件等共享任何数据,例如。两者都只访问超过控件/线程的数据,(这实际上意味着没有 synchronize(),没有 TThread.waitFor(),没有 OnTerminate() ),那么就没有必要在主线程之前等待后台线程终止表单等被销毁,完成部分运行并且主线程退出。主线程最终会调用 ExitProcess(),所有后台线程都会被操作系统销毁,无论它们处于什么状态。
  • 我还没有找到问题所在(它非常很少见),但是你给了我一些关于要检查的东西的好信息。谢谢。
【解决方案2】:

您确定工作线程已终止,并且主线程没有等待它完成吗?

【讨论】:

  • 我不确定发生了什么,我只见过一次这个问题,但我想确保它不会在客户的机器上再次出现。如果我故意让工作线程永远不会终止(通过在 C++ 中添加“while (true);”循环),应用程序仍然会干净地关闭,所以我认为问题不在于主线程正在等待工人终止。
  • 等一下。您添加了一个 while 循环,以确保线程永远不会终止。但是其他地方可以调用 TThread.Terminate。所以你所做的是让它不太可能干净地关闭。难怪你的应用坏了。
  • @Warren P:我想你可能误解了。请参阅我对您的回答的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-02
相关资源
最近更新 更多