我们的程序在程序开头创建一个后台线程。后台线程使用Indy进行一些数据库完整性检查并检查Internet中的内容。 10秒后,后台线程应该完成,因为FreeOnTerminate为真,它也会自行清理。
我们注意到,在某些情况下,如果用户过快关闭程序,则该过程仍然有效,直到后台线程完成。
由于我们无法完全重现这个问题,我创建了一个演示项目来尝试一些事情:
type
TBackgroundThread = class(TThread)
protected
procedure Execute; override;
end;
{ TForm1 }
var
bt: TBackgroundThread;
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
begin
// Create a background thread which runs X seconds and then terminates itself.
bt := TBackgroundThread.Create(false);
bt.FreeOnTerminate := true;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
// The user closes the app while the background thread is still active
Sleep(2000);
Close;
end;
{ TBackgroundThread }
procedure TBackgroundThread.Execute;
var
i: integer;
x: cardinal;
begin
inherited;
// Simulate some work that the background thread does
x := MaxInt;
for i := 0 to MaxInt do
begin
x := Random(x);
end;
end;
结果让我感到有些惊讶:关闭MainForm后,进程将立即终止,后台线程将被硬杀死。
现在我有几个问题:
关闭MainForm(=退出主线程)后,我应该通过.Terminate手动终止所有创建的线程还是自动完成?
我的帖子只检查Self.Terminated还是应该检查Application.Terminated?
为什么关闭应用程序时,如上所示的忙线程会立即被杀死?我期望Project1.exe进程将运行,直到所有线程都由他们自己完成。 (并且如上所述,我们已经看到一个应用程序,其中主窗体被关闭,但是一个线程阻止了关闭过程。)
那么,由于正在运行的后台线程,我们的实际应用程序的进程怎么可能不会终止?可能它与互联网的东西有关,这可能导致应用程序等到达到连接超时?
答案 0 :(得分:3)
关闭主窗体并不是退出主线程的同义词。表单关闭后代码继续运行。特别是,单位最终确定。
如果你处理测试线程的OnTerminate
事件,或者在Terminate
方法中放置一个断点,你会发现当你的时候没有自动调用它程序退出。你必须自己打电话。但请注意,由于Terminate
被调用,线程不会停止运行。它会继续运行,直到它自行停止或强行终止。致电WaitFor
等待它终止。
不要费心检查Application.Terminated
;线程的属性应该足够了。
当程序退出时,你的线程会被强制终止,因为最终你的程序会调用ExitProcess
,操作系统所做的其中一件事就是终止所有其他线程。它没有对它们调用Terminate
因为操作系统不了解Delphi类和方法。
您必须进行更多调试,以确定您的计划未及时终止客户的原因。你说你不能在内部重现这个问题,而且你已经编写了一个没有出现问题的测试程序。您必须找到一位能够配合您进一步调试工作的客户。你真的知道它是什么线索,或者只是猜测到目前为止?