Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does background threads prevent the process of being terminated?

Our program creates a background thread at the beginning of the program. The background thread does some database integrity checks and checks for stuff in the Internet using Indy. After 10 seconds, the background thread should be finished and since FreeOnTerminate is true, it will also clean itself up.

We have noticed that in some cases, if the user closes the program too quickly, the process will still be alive until the background thread is finished.

Since we couldn't exactly reproduce the issue, I have created a demo project to try a few things:

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;

The result is a bit surprising to me: After I close the MainForm, the process will be immediately terminated and the background thread will get hard-killed.

Now I have a few questions about this:

  1. After the closing of the MainForm (= exit of the main thread), should I manually terminate all created threads via .Terminate or will that be done automatically?

  2. Shall my threads only check for Self.Terminated or should they also check for Application.Terminated ?

  3. Why does my busy thread as shown above gets immediately killed when I close the application? I expected that the process Project1.exe will run until all threads have finished by themselfes. (And as described above, we had seen an application where the main form is closed, but a thread is preventing the process of being closed).

  4. How is it possible then, that our real application's process does not terminate because of a running background thread? Might it have something to do with the Internet stuff, which might cause the app to wait until a connection timeout is reached?

like image 811
Daniel Marschall Avatar asked May 23 '14 12:05

Daniel Marschall


People also ask

What happens to threads when process terminated?

Once ExitProcess() is called, the OS will stop ALL threads of the process, no matter what state they are in, before deallocating any memory, (like the memory containing your flag). The thread that calls ExitProcess() never has control returned to it.

Which kind of threads has the ability to prevent the current application from terminating?

Foreground threads are those threads that keep running even after the application exits or quits. It has the ability to prevent the current application from terminating.

Which threads execute in the foreground (*) by default (*) foreground threads Unlike background ones keep the managed execution environment running?

By default, threads are foreground threads, meaning they keep the application alive for as long as any one of them is running.

What are background threads?

In programming, a background thread is a thread that runs behind the scenes, while the foreground thread continues to run. For instance, a background thread may perform calculations on user input while the user is entering information using a foreground thread.


1 Answers

Closing the main form is not synonymous with exiting the main thread. Code continues to run after the form is closed. In particular, units are finalized.

If you handle your test thread's OnTerminate event, or put a breakpoint in the Terminate method, you'll see that it's not called automatically when your program exits. You'll have to call it yourself. But note also that a thread doesn't stop running just because Terminate is called. It continues running until it stops itself or it's terminated forcefully. Call WaitFor to wait for it to terminate.

Don't bother checking Application.Terminated; the thread's property should be sufficient.

Your thread gets terminated forcefully as your program exits because eventually your program calls ExitProcess, and one of the things the OS does there is to terminate all other threads. It doesn't call Terminate on them because the OS doesn't know about Delphi classes and methods.

You'll have to do some more debugging to determine why your program doesn't terminate promptly for your customers. You say you can't reproduce the problem in house, and you've written a test program that doesn't exhibit the problem, either. You'll have to find a customer who will cooperate with your further debugging efforts. Do you really know it's the thread that's holding things up, or is that just a guess so far?

like image 140
Rob Kennedy Avatar answered Nov 15 '22 07:11

Rob Kennedy