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

时间:2014-05-23 12:39:47

标签: multithreading delphi indy terminate

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

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

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

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后,进程将立即终止,后台线程将被硬杀死。

现在我有几个问题:

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

  2. 我的帖子只检查Self.Terminated还是应该检查Application.Terminated?

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

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

1 个答案:

答案 0 :(得分:3)

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

如果你处理测试线程的OnTerminate事件,或者在Terminate方法中放置一个断点,你会发现当你的时候没有自动调用它程序退出。你必须自己打电话。但请注意,由于Terminate被调用,线程不会停止运行。它会继续运行,直到它自行停止或强行终止。致电WaitFor等待它终止。

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

当程序退出时,你的线程会被强制终止,因为最终你的程序会调用ExitProcess,操作系统所做的其中一件事就是终止所有其他线程。它没有对它们调用Terminate因为操作系统不了解Delphi类和方法。

您必须进行更多调试,以确定您的计划未及时终止客户的原因。你说你不能在内部重现这个问题,而且你已经编写了一个没有出现问题的测试程序。您必须找到一位能够配合您进一步调试工作的客户。你真的知道它是什么线索,或者只是猜测到目前为止?