多线程(TThread)Delphi应用程序无法终止

7
我编写了一个应用程序(使用Delphi 2009),允许用户选择一系列可以在多个不同系统上运行的查询。为了允许并发运行查询,每个查询都在自己的线程中运行,使用TADOQuery对象。这一切都很好。
我的问题是,当我尝试关闭应用程序时,如果仍有查询在运行(因此存在单独的线程),就会出现问题。当我创建每个线程时,我将线程的THandle记录在数组中。当我尝试关闭应用程序时,如果任何线程仍在运行,则检索线程的句柄并将其传递给TerminateThread,理论上应该终止线程并允许应用程序关闭。但是,这并没有发生。主窗体的onClose事件被触发,看起来应用程序正在关闭,但进程仍然处于活动状态,我的Delphi界面似乎仍在运行(即“运行”按钮变灰,调试视图处于活动状态等)。除非我手动结束进程(在Delphi中按Ctrl-F2或通过任务管理器),否则我无法控制Delphi。
我使用TerminateThread是因为查询可能需要很长时间才能运行(在处理数百万条记录的情况下可能需要几分钟,在最终用户环境中完全可能),而当它正在运行时,除非我弄错了,否则线程将无法检查Terminated属性,因此除非查询已返回,否则线程将无法在Terminated属性设置为True时结束自身,因此我无法以通常的方式(即通过检查Terminated属性)终止线程。也许用户希望在运行大型查询时退出应用程序,在这种情况下,我需要应用程序立即结束(即所有运行中的线程立即终止),而不是强制它们等待所有查询完成运行,因此TerminateThread是理想的,但实际上并没有终止线程!
有人能帮忙吗?有人知道为什么TerminateThread不能正常工作吗?有人可以建议任何方法来立即终止运行大型ADO查询的线程吗?
3个回答

8

您应该可以通过挂钩OnFetchProgress事件并将Eventstatus变量设置为esCancel来取消ADO查询。这应该会导致查询终止,并允许线程优雅地关闭,而不必使用TerminateThread。


这看起来是前进的方向。我过去一周一直在做其他事情,但在接下来的几天里我会研究一下这个。你有这方面任何源代码的例子吗? - Jeedee

6

如果您使用TADOQuery的线程,那么也许您应该考虑使用ADO的异步选项。

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

当您的应用程序关闭时,您可以调用:
ADOQuery1.cancel;

我已经使用线程编写了该应用程序。不幸的是,重新编写查询以这种方式执行需要太长时间,而且我也不确定它是否能按照我的意愿正常工作。 - Jeedee

5

在msdn中可以看到,使用TerminateThread是很危险的。

TerminateThread是一个非常危险的函数,只有在极端情况下才应该使用。只有当你知道目标线程正在做什么,并且你控制着目标线程可能正在运行的所有代码时,才应该调用TerminateThread。

但它也非常有效地终止线程。你确定你的结论是正确的吗?也许线程被杀死了,但另一个线程仍在运行?也许你的句柄不是线程句柄?你能展示一些代码吗?或者更好的是:一个我们可以自己试用的小例子?


我知道使用TerminateThread的警告,但我已经在上面解释了我的原因。当没有线程启动运行查询时,应用程序关闭得很好,但是当我有一个单独的线程运行时,它不会关闭,所以肯定是查询线程引起了问题。我创建查询线程并将句柄存储在数组中,如下所示: newThread := TQueryThread.create(true); threadStatusArr[index].threadHandle := newThread.handle; newthread.resume;然后,我从数组中检索句柄并将其传递给TerminateThread。 - Jeedee

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