I got a doubt that I wasnt able to solve online or in my delphi books. Look at this.
Case 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;
And this is the VCL implementation:
procedure TForm1.Button1Click(Sender: TObject);
var s: Test;
begin
s := Test.Create;
s := nil;
end;
I open the program, I click the button, I wait 5 seconds and I see the file on the desktop. But if I open the program, I click the button and after 2 seconds I close the program, I don't see the file anymore (after the 5 seconds).
I read nick hodges' more coding in delphi and he said that this kind of thread is F&F ("Fire and forget") because once started we let it go and it will cleanup by itself. If I close the program before its termination, will it be properly killed?
Case 2. Out of curiosity I've written this code as well:
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;
That is the code in Case 1 but with less typing because I've used a Task. In this case things are different!
If I run the program, click the button and wait 5 seconds I can see the file. If I run the program, click the button and then I close the program after 2 seconds (or in any case, before 5 seconds) I still see the text file!
As already asked above, I'd like to know if (in Case 1) is fine to just close the program before the termination of the thread. Because I thought that I could have written this:
procedure TForm1.FormDestroy(Sender: TObject);
begin
if not(s.Terminated) then
s.Terminate;
end;
Basically I am not sure if I have to call Terminate
in code or if it's called automatically somehow when the program dies. From what I've seen by my tests, this affects only TThread descendants and NOT Tasks.
This has nothing to do with files. It is the unfortunate difference how the Delphi runtime handles threads, compared to how it handles tasks.
When you exit a VCL application, the background threads are just killed off. The application does not wait for them, it just ends. If you want to wait for them, you will have to write the code yourself.
A VCL application, however, will wait (for all eternity, if necessary) for all the tasks that were put in the default thread pool (System.Threading.TThreadPool.Default
).
Consider this example VCL application: Empty form with two buttons:
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;
Run this application in your debugger. You will notice that for Button1, your application will exit immediately. For Button2, your program appears to be gone (the form has been closed), but it's still running! Finally, after five seconds, your debugger will break on Winapi.Windows.DebugBreak()
.
Bonus:
Change TTask.Run(backgroundStuff);
to TTask.Run(backgroundStuff, TThreadPool.Create());
and see what happens.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With