【问题标题】:Multithreaded (TThread) Delphi application will not terminate多线程 (TThread) Delphi 应用程序不会终止
【发布时间】:2026-01-12 08:20:06
【问题描述】:

我编写了一个应用程序(使用 Delphi 2009),它允许用户选择一系列可以在多个不同系统上运行的查询。为了允许查询同时运行,每个查询都在自己的线程中运行,使用TADOQuery 对象。这一切都很好。

我遇到的问题是当我尝试在查询仍在运行时关闭应用程序(因此一个单独的线程处于活动状态)。当我创建每个线程时,我将线程的THandle 记录在一个数组中。当我尝试关闭应用程序时,如果任何线程仍在运行,我会检索线程的句柄并将其传递给TerminateThread,理论上它应该终止线程并允许应用程序关闭。但是,这不会发生。主窗体的onClose 事件被触发,看起来应用程序正在关闭,但进程仍然处于活动状态,我的 Delphi 界面看起来好像应用程序仍在运行(即“运行”按钮灰显,调试视图处于活动状态等) .在我手动结束进程(在 Delphi 中按 Ctrl-F2 或通过任务管理器)之前,我无法将控制权交还给 Delphi。

我正在使用TerminateThread,因为查询可能需要很长时间才能运行(在我们处理一百万条左右的记录的情况下需要几分钟,这在最终用户环境中是完全可能的),而它正在运行,除非我弄错了,否则线程将无法检查 Terminated 属性,因此如果在查询返回之前将其设置为 True 将无法自行结束,所以我不能以通常的方式终止线程(即通过检查 Terminated 属性)。可能是用户想要在运行大型查询时退出应用程序,在这种情况下,我需要应用程序立即结束(即所有正在运行的线程立即终止),而不是强制它们等到所有查询都完成完成运行,所以TerminateThread 是理想的,但它实际上并没有终止线程!

有人可以帮忙吗?有谁知道为什么TerminateThread 不能正常工作?谁能提出任何建议让运行大型 ADO 查询的线程立即终止?

【问题讨论】:

    标签: delphi multithreading ado


    【解决方案1】:

    您应该能够通过挂钩 OnFetchProgress 事件并将 Eventstatus 变量设置为 esCancel 来取消 ADO 查询。这应该会导致您的查询终止并允许线程正常关闭,而不必求助于使用 TerminateThread。

    【讨论】:

    • 这看起来像是前进的方向。过去一周左右我一直在做其他事情,但我会在接下来的几天里研究这个。你有这方面的任何来源的例子吗?
    【解决方案2】:

    与其在 TADOQuery 中使用线程,不如考虑使用 ADO 的异步选项。

    ADOQuery1.ExecuteOptions := [eoAsyncExecute, eoAsyncFetch, eoAsyncFetch];
    

    然后当你的应用程序关闭时,你可以调用:

    ADOQuery1.cancel;
    

    【讨论】:

    • 我已经使用线程编写了应用程序。不幸的是,像这样重写查询需要很长时间,而且我不确定它是否会按照我想要的方式工作。
    【解决方案3】:

    正如您在 msdn 中看到的那样,使用 TerminateThread 是危险的。

    TerminateThread 是危险的 仅应在中使用的功能 最极端的情况。你应该 仅当您知道时才调用 TerminateThread 目标线程到底是什么 做,你控制所有的代码 目标线程可能 正在运行 终止。

    但它在杀死线程方面也非常有效。你确定你的结论是对的吗?也许线程被杀死了,但另一个线程仍在运行?也许您的句柄不是线程句柄?你能给我们看一些代码吗?甚至更好:我们可以自己尝试一个小的工作示例?

    【讨论】:

    • 我知道有关使用 TerminateThread 的警告,但在上面解释了我这样做的原因。当没有线程被启动来运行查询时,应用程序可以正常关闭,但是当我运行单个线程时不会关闭,因此绝对是导致问题的查询线程。我创建查询线程并将句柄存储在这样的数组中: newThread := TQueryThread.create(true); threadStatusArr[index].threadHandle := newThread.handle;新线程.resume;然后我从数组中检索句柄并将其传递给 TerminateThread。