Delphi - 应用程序退出时未释放(但已终止)的线程会发生什么?

4
我有一个多线程应用程序,在应用程序结束时遇到了一些小问题:我可以通过在Form1.OnDestroy事件处理程序中调用TThread.Terminate方法来正确终止线程,但是终止需要一些时间,因此我无法释放内存(通过TThread.Free方法)。 不幸的是,由于某种其他原因,我必须将TThread.FreeOnTerminate属性设置为false,因此线程对象在线程终止后不会自动销毁。
我的问题可能有点傻,我早就应该知道它了,但这样做是否正常并且线程将自动销毁(因为应用程序只是结束),还是存在问题并且内存将被“丢失”?感谢您的解释。

3
线程课程一:不要终止一个线程;发信号通知它停止,然后等待其结束。 - Jeroen Wiert Pluimers
4
TThread.Terminate 方法通过设置 Terminated 标志实际上实现了退出操作,当你在代码中检查这个标志时,就是一个退出信号。 - Nat
我的问题是我重写了线程的析构函数,并且没有等待线程终止。我承认我还在学习如何使用线程,有些忽视了正好符合我需要的WaitFor方法...所以在FormDestroy中,我只需请求线程终止(在线程的Execute方法中我经常检查Terminated,所以我知道它真的会终止),然后就完成了...这就是为什么我提出了这个问题...非常感谢所有的回答和评论,它们对我帮助很大... - Ondra C.
1
在调用Terminate()方法之后但在调用Free()方法之前,调用线程的WaitFor()方法。 - Remy Lebeau
只需将 FreeOnTerminate 设置为 true 并在 try except 块中调用 Terminate - Niyoko
5个回答

7

在关闭应用程序的其余部分之前,您应该等待线程终止,否则共享资源可能会在线程结束时被释放,从而可能导致一系列访问冲突。等待线程终止后,您可以释放它。实际上,这就是TThread析构函数为您完成的。

如果没有共享资源,那么当然可以让它自行死亡。即使线程在主线程之后终止,只要所有线程退出,程序就会终止。与线程对象相关联的任何内存都将随其他内容一起被清理并返还给操作系统。

但是,要小心!如果您的线程需要花费很长时间才能退出,它可能会成为僵尸进程,一直在运行而没有GUI界面。这就是为什么在线程循环中非常重要的检查Terminated标志,并退出线程。

N@


7
你的代码过于复杂。自从引入 TThread 以来,析构函数已经自己调用了 TerminateWaitFor。简单的 Free(或 FreeAndNil)就足够了。如果线程类有一个重载的析构函数,它应该在其中调用 TerminateWaitFor,因为它不能在线程过程结束之前销毁字段。把所有这些留给线程类的用户太危险了。 - mghie
真的。这是为了安全起见...我曾经遇到过程序在TThread析构函数中挂起的情况,因为线程已经终止,但它又试图再次终止它(等待无限时间以进行永远不会发生的关闭),因此需要这段代码。也许我在线程终止和线程清理代码执行之间捕捉到了该线程。 - Nat
1
感谢您在这里发布的代码,再加上mghie的评论,它对我帮助最大。 - Ondra C.
已解决Nat的问题,所以他现在不在这里,正在拍照。 - user30478

4

你的问题并不愚蠢或简单 - 阅读MSDN文章。总之,如果你想保险起见,在退出应用程序之前最好等待后台线程终止。


1
线程最终将会终止,Windows 会清理任何剩余的内存。然而,你最好等待线程终止,因为这正是 Windows 将要做的。你的应用程序可能会“看起来”已经关闭,因为所有窗口可能已经被关闭/隐藏,但是应用程序进程直到所有线程都完成后才会终止...

0

当一个进程终止时,操作系统将回收所有分配的内存并关闭所有打开的句柄。在关闭应用程序的非常特殊的情况下,您不需要担心内存泄漏问题。操作系统也会关闭所有打开的句柄,至少在理论上是这样的。考虑到所有这些因素,您可以安全地在窗体析构函数中终止线程(使用TerminateThread(MyThread.Handle)),然后再杀死其他共享资源。请问自己以下几个问题:

  1. 线程正在做什么?随时终止它是否安全?例如:如果线程正在进行任何磁盘写入操作,则不能简单地杀死它,因为可能会使磁盘上的文件处于不一致状态。
  2. 您是否正在使用任何Windows无法自动释放的资源?这里想不出一个好的例子...

如果两者都很安全,您可以使用TerminateThread而不必等待线程自然终止。更安全的方法可能是综合方法,也许您应该给线程一个自然终止的机会,如果它在5秒内没有终止,则强制终止它。

*) 我在谈论那些只能在进程终止时才能证明泄漏的内存,例如你杀死而没有给予适当关闭机会的线程,或者你不释放的全局单例类。所有其他未记录的内存都需要被追踪并修复,因为它是一个错误。

**) 不幸的是,Windows 操作系统并非无错。例如:任何在 Windows 平台上使用串行设备的人都知道它有多容易陷入“锁定”状态,需要重新启动才能使其正常工作。从技术上讲,这也是一个句柄,结束锁定它的应用程序应该解锁它。


0

为什么在创建线程时不增加一个变量,在销毁事件中等待线程完成,然后减少变量,在应用程序终止时只需执行Application.processmessages?

为什么您的线程不是freeonterminate=true?所有共享资源都可以处理到关键部分。

此致敬礼,


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接