【发布时间】:2014-07-12 19:57:01
【问题描述】:
我们的程序在程序开始时创建了一个后台线程。后台线程使用 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 进程将一直运行,直到所有线程都自行完成。 (如上所述,我们看到了一个应用程序,其中主窗体已关闭,但一个线程正在阻止进程被关闭。
那么,我们真正的应用程序的进程怎么可能不会因为后台线程运行而终止呢?可能与互联网有关,这可能导致应用等待连接超时?
【问题讨论】:
-
嗨。这是很多问题,但我们都去过那里。我建议您阅读 Joe Duffy 的书“Windows 上的并发编程”以了解基本概念(虽然不是那么基本),然后阅读 Delphi 文档。
-
我认为 Indy 正在阻止您的线程立即完成。我猜你可以使用超时阻塞套接字。
-
但是@Lurd,阻塞套接字是否会阻止
ExitProcess杀死线程?我对此表示怀疑。 -
@RobKennedy 好吧,有一些版本的 Indy 带有可怕的析构函数,如果被调用,它们会等到所有 TidThread 等实例都被终止。由于这些原因,我避免将 Indy 组件添加到表单和数据模块上,而只是在需要使用它们的任何线程中创建它们。如果狡猾的析构函数永远不会被调用,它们就无法通过阻止到达 ExitProcess() 来阻止应用程序关闭进程。
-
一般来说 - 不要将线程子系统组件插入表单。如果这样做,在应用程序关闭时释放拥有的表单将尝试释放组件,如果内部线程,可能会卡住等待线程终止。
标签: multithreading delphi indy terminate