后台线程何时阻止终止进程?

Dan*_*all 6 delphi multithreading indy terminate

我们的程序在程序开头创建一个后台线程.后台线程使用Indy进行一些数据库完整性检查并检查Internet中的内容.10秒后,后台线程应该完成,因为FreeOnTerminate为true,它也会自行清理.

我们注意到,在某些情况下,如果用户过快地关闭程序,则该过程仍然有效,直到后台线程完成.

由于我们无法完全重现该问题,因此我创建了一个演示项目来尝试一些事情:

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;
Run Code Online (Sandbox Code Playgroud)

结果有点令我惊讶:关闭MainForm后,进程将立即终止,后台线程将被硬杀死.

现在我有几个问题:

  1. 关闭MainForm(=主线程的退出)后,我应该通过.Terminate手动终止所有创建的线程还是自动完成?

  2. 我的线程只能检查Self.Terminated还是应该检查Application.Terminated?

  3. 当我关闭应用程序时,为什么上面显示的繁忙线程会立即被杀死?我期望Project1.exe进程将运行,直到所有线程都由他们自己完成.(并且如上所述,我们已经看到了一个主窗体关闭的应用程序,但是一个线程阻止了关闭过程).

  4. 那么,由于运行后台线程,我们的实际应用程序的进程是如何终止的呢?可能它与互联网的东西有关,这可能导致应用程序等到达到连接超时?

Rob*_*edy 3

关闭主窗体并不等同于退出主线程。表单关闭后代码继续运行。特别是,单位已经最终确定。

如果您处理测试线程的OnTerminate事件,或者在方法中放置断点Terminate,您将看到程序退出时不会自动调用它。你必须自己调用它。但还要注意,线程不会仅仅因为Terminate被调用而停止运行。它会继续运行,直到自行停止或被强制终止。调用WaitFor以等待其终止。

不用费心去检查Application.Terminated;线程的属性应该足够了。

当程序退出时,您的线程会被强制终止,因为最终您的程序会调用ExitProcess,而操作系统所做的事情之一就是终止所有其他线程。它不会调用Terminate它们,因为操作系统不知道 Delphi 类和方法。

您必须进行更多调试,以确定为什么您的程序没有为您的客户立即终止。您说您无法在内部重现该问题,并且您编写的测试程序也没有表现出该问题。您必须找到愿意配合您进一步调试工作的客户。你真的知道这是支撑事情的线索,还是到目前为止这只是一个猜测?

  • 在设置了“FreeOnTerminate”的线程上调用“Waitfor”是不安全的。请参阅[销毁 TThread 对象的正确方法](http://stackoverflow.com/a/1092831/576719)。 (2认同)