delphi - 程序终止后的 Delphi 任务和线程
问题描述
我怀疑我无法在线或在我的德尔福书中解决。看这个。
情况1。
type
Test = class(TThread)
protected
procedure Execute; override;
public
constructor Create;
end;
constructor Test.Create;
begin
inherited Create(false);
FreeOnTerminate := true;
end;
procedure Test.Execute;
begin
inherited;
Sleep(5000);
TFile.WriteAllText('C:\Users\EmmaVMWare\Desktop\ts.txt', 'test2');
end;
这是 VCL 的实现:
procedure TForm1.Button1Click(Sender: TObject);
var s: Test;
begin
s := Test.Create;
s := nil;
end;
我打开程序,单击按钮,等待 5 秒钟,然后在桌面上看到文件。但是如果我打开程序,我单击按钮,2 秒后我关闭程序,我不再看到文件(5 秒后)。
我在 delphi 中阅读了 nick hodges 的更多编码,他说这种线程是 F&F(“一劳永逸”),因为一旦开始我们就放手,它会自行清理。如果我在程序终止之前关闭程序,它会被正确杀死吗?
案例2。 出于好奇,我也写了这段代码:
procedure TForm1.Button1Click(Sender: TObject);
var s: ITask;
begin
s := TTask.Run(procedure
begin
Sleep(5000);
TFile.WriteAllText('C:\Users\EmmaVMWare\Desktop\aa.txt', 'test');
end);
end;
那是案例 1 中的代码,但由于我使用了任务,因此输入较少。在这种情况下,情况就不同了!
如果我运行程序,单击按钮并等待 5 秒钟,我可以看到该文件。如果我运行程序,单击按钮,然后在 2 秒后(或者无论如何,在 5 秒之前)关闭程序,我仍然可以看到文本文件!
- 任务。一旦启动,它会一直运行到最后,无论我是否在程序终止之前关闭程序。
- TThread 子类。一旦启动,它将一直运行到最后,但是如果我在程序终止之前关闭程序,它就会死掉(?)
正如上面已经问过的,我想知道(在案例 1 中)是否可以在线程终止之前关闭程序。因为我认为我可以这样写:
procedure TForm1.FormDestroy(Sender: TObject);
begin
if not(s.Terminated) then
s.Terminate;
end;
基本上我不确定我是否必须调用Terminate
代码,或者当程序死亡时它是否会以某种方式自动调用。从我的测试中看到,这仅影响 TThread 后代而不影响任务。
解决方案
这与文件无关。不幸的是,Delphi 运行时处理线程的方式与其处理任务的方式不同。
当你退出一个 VCL 应用程序时,后台线程就被杀死了。应用程序不等待他们,它只是结束。如果您想等待它们,则必须自己编写代码。
然而,VCL 应用程序将等待(如果有必要,会一直等待)所有放在默认线程池 ( System.Threading.TThreadPool.Default
) 中的任务。
考虑这个示例 VCL 应用程序:带有两个按钮的空表单:
implementation uses System.Threading, Winapi.Windows;
procedure TForm1.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread(backgroundStuff).Start();
Application.Terminate();
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
TTask.Run(backgroundStuff);
Application.Terminate();
end;
procedure TForm1.backgroundStuff();
begin
Sleep(5000);
Winapi.Windows.DebugBreak();
end;
在您的调试器中运行此应用程序。您会注意到对于Button1,您的应用程序将立即退出。对于Button2,您的程序似乎已经消失(表单已关闭),但它仍在运行!最后,五秒钟后,您的调试器将中断Winapi.Windows.DebugBreak()
。
奖励:
更改TTask.Run(backgroundStuff);
并TTask.Run(backgroundStuff, TThreadPool.Create());
查看会发生什么。
推荐阅读
- selenium - isDisplayed() 不工作,正在使用 pagefactory
- ios - 如何在 UICollectionViewHeader 中添加 UIView (swift 5)
- django - 'QueryDict' 对象没有属性 'first_name'
- python - 裁剪多边形并将其转换为灰度
- java - Maven version:update 不更新给定版本,它与 repo 比较并更新到最新而不是给定版本
- apache-spark - Spark Yarn Cluster - hive 列数大于 200 时出现 java.lang.StackOverflowError 错误
- elasticsearch - Grafana图总计数显示为列表?
- php - 使用 Laravel Excel 制作相当于 pandas.read_csv(file) 的内容
- r - Xl.Read.File 函数不会读取所有行
- ios - 如果设备上仅设置了设备代码,IOS 无法创建私钥?