Multithreading 后台线程何时阻止进程终止?
我们的程序在程序开始时创建一个后台线程。后台线程使用Indy进行一些数据库完整性检查和Internet中的内容检查。10秒后,背景线程应该完成,因为FreeOnTerminate为true,所以它也会自行清理 我们注意到,在某些情况下,如果用户关闭程序的速度过快,则在后台线程完成之前,进程仍将处于活动状态 由于我们无法准确再现该问题,我创建了一个演示项目来尝试以下几点:Multithreading 后台线程何时阻止进程终止?,multithreading,delphi,indy,terminate,Multithreading,Delphi,Indy,Terminate,我们的程序在程序开始时创建一个后台线程。后台线程使用Indy进行一些数据库完整性检查和Internet中的内容检查。10秒后,背景线程应该完成,因为FreeOnTerminate为true,所以它也会自行清理 我们注意到,在某些情况下,如果用户关闭程序的速度过快,则在后台线程完成之前,进程仍将处于活动状态 由于我们无法准确再现该问题,我创建了一个演示项目来尝试以下几点: type TBackgroundThread = class(TThread) protected proce
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之后,进程将立即终止,后台线程将被硬终止
现在我有几个问题:
关闭主窗体并不等同于退出主线程。关闭表单后,代码将继续运行。特别是,这些单位已最后确定 如果处理测试线程的
OnTerminate
事件,或者在Terminate
方法中放置断点,您将看到程序退出时不会自动调用它。你得自己说了。但还要注意,线程不会因为调用了Terminate
而停止运行。它继续运行,直到它自身停止或强制终止。调用WaitFor
等待它终止
不要费心检查应用程序。已终止;线程的属性应该足够了
当程序退出时,您的线程会被强制终止,因为最终您的程序会调用ExitProcess
,操作系统要做的一件事就是终止所有其他线程。它不会对它们调用Terminate
,因为操作系统不知道Delphi类和方法
您必须进行更多的调试,以确定为什么您的程序不能为您的客户及时终止。你说你不能在家里重现这个问题,你已经编写了一个测试程序,也没有显示出这个问题。您必须找到一位客户,他将配合您进一步的调试工作。你真的知道是这根线支撑着一切吗,还是这只是目前的猜测?嗨。这是很多问题,但我们都经历过。我建议您阅读Joe Duffy的书“Windows上的并发编程”,学习基本概念(虽然不是那么基本),然后阅读Delphi文档。我认为Indy正在阻止您的线程立即完成。我猜你可以使用超时的阻塞套接字。但是@Lurd,阻塞套接字是否会阻止ExitProcess
终止线程?“我对此表示怀疑。”RobKennedy说,“嗯,有一些版本的Indy带有可怕的析构函数,如果调用这些析构函数,就要等到所有的TidThread等实例都被终止。出于这些原因,我避免将Indy组件链接到表单和数据模块上,而只是在线程需要使用它们的时候创建它们。如果不可靠的析构函数从未被调用,它们将无法阻止访问ExitProcess(),从而阻止app close进程。一般来说,不要将线程子系统组件链接到窗体上。如果执行此操作,在app close上释放所属窗体将尝试释放组件,如果该组件是内部线程,则可能会在等待线程终止时卡住。在设置了FreeOnTerminate
的线程上调用Waitfor
是不安全的。看,谢谢。现在,很多事情变得更加清楚了。我重构了大部分代码,不再使用FreeOnTerminate
。相反,我将所有创建的线程写入一个ObjectList,每个元素都将在程序终止时使用Terminate
+WaitFor
+Free
进行处理(完成单元)。在每个线程中,我都会定期检查Self.Terminated
。