如何优雅地停止长时间执行的线程?
Posted
技术标签:
【中文标题】如何优雅地停止长时间执行的线程?【英文标题】:How to stop long executing threads gracefully? 【发布时间】:2008-10-31 23:51:49 【问题描述】:我在使用 Delphi 时遇到了线程问题。我想这在其他语言中也很常见。我在线程中执行了一个很长的过程,该过程填充了主窗口中的列表。但是如果同时一些参数发生变化,那么我应该停止当前正在执行的线程并从头开始。 Delphi 建议通过设置 Terminated:=true 并在线程中检查该变量的值来终止线程。但是我的问题是,长执行部分隐藏在库调用中,在此调用中我无法检查 Terminated 变量。因此我不得不等待这个库调用完成,这会影响整个程序。
在这种情况下,首选的方法是什么?我可以立即杀死线程吗?
【问题讨论】:
什么是长时间运行的库调用? 【参考方案1】:首选方法是修改代码,使其在不检查取消的情况下不会阻塞。
既然你不能修改代码,你就不能那样做;您要么必须忍受后台操作(但您可以将其与任何 UI 解除关联,这样它的完成将被忽略);或者,您可以尝试终止它(TerminateThread API 将粗暴地终止任何给定其句柄的线程)。终止不是干净的,但是,就像 Rob 所说的那样,线程持有的任何锁都将被放弃,并且受此类锁保护的任何跨线程状态都可能处于损坏状态。
您可以考虑在单独的可执行文件中调用该函数吗?也许使用 RPC(管道,TCP,而不是由于相同的锁问题而共享内存),以便您可以终止进程而不是终止线程?进程隔离将为您提供更多保护。只要你不依赖像互斥锁这样的跨进程命名的东西,它应该比杀死一个线程安全得多。
【讨论】:
这听起来是个好建议。在另一个进程中进行此调用将在没收它后留下任何痕迹。【参考方案2】:线程需要合作以实现正常关闭。我不确定 Delphi 是否提供中止另一个线程的机制,但此类机制在 .NET 和 Java 中可用,但应被视为最后的选择,并且应用程序的状态在使用后是不确定的。
如果您可以在任意点终止线程,那么您可以在它持有内存分配器中的锁时终止它(例如)。当您的主线程下一次需要访问该锁时,这将使您的程序处于挂起状态。
【讨论】:
【参考方案3】:如果您不能修改代码来检查是否终止,那么只需将其优先级设置得很低,并在它返回时忽略它。
【讨论】:
【参考方案4】:我写这个是为了回复similar question:
我使用基于异常的技术 这对我来说效果很好 Win32 应用程序的数量。
要终止一个线程,我使用 QueueUserAPC 将呼叫排队 抛出异常的函数。 但是,抛出的异常 不是从类型派生的 “例外”,所以只会被 我的线程的包装过程。
我已经非常成功地将它与 C++Builder 应用程序一起使用。我不了解 Delphi 与 C++ 异常处理的所有微妙之处,但我希望它可以很容易地修改以工作。
【讨论】:
以上是关于如何优雅地停止长时间执行的线程?的主要内容,如果未能解决你的问题,请参考以下文章
如果优雅地关闭ExecutorService提供的java线程池