自动或手动释放TThread

Ste*_*eve 9 delphi multithreading delphi-7 tthread

我的程序中有一个主线程和一个单独的线程.如果单独的线程在主线程之前完成,它应该自动释放.如果主线程首先完成,它应该释放单独的线程.

我知道FreeOnTerminate,我读过你必须小心使用它.

我的问题是,以下代码是否正确?

procedure TMyThread.Execute;
begin
  ... Do some processing

  Synchronize(ThreadFinished);

  if Terminated then exit;

  FreeOnTerminate := true;
end;

procedure TMyThread.ThreadFinished;
begin
  MainForm.MyThreadReady := true;
end;

procedure TMainForm.Create;
begin
  MyThreadReady := false;

  MyThread := TMyThread.Create(false);
end;

procedure TMainForm.Close;
begin
  if not MyThreadReady then
  begin
    MyThread.Terminate;
    MyThread.WaitFor;
    MyThread.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

mgh*_*hie 8

您可以将其简化为:

procedure TMyThread.Execute;
begin
  // ... Do some processing
end;

procedure TMainForm.Create;
begin
  MyThread := TMyThread.Create(false);
end;

procedure TMainForm.Close;
begin
  if Assigned(MyThread) then
    MyThread.Terminate;
  MyThread.Free;
end;
Run Code Online (Sandbox Code Playgroud)

说明:

  • FreeOnTerminate手动使用或释放线程,但绝不要同时使用.线程执行的异步性质意味着您存在不释放线程的风险或(更糟糕的是)执行两次.在完成执行后保持线程对象没有风险,并且调用Terminate()已经完成的线程也没有风险.

  • 无需同步访问仅从一个线程写入并从另一个线程读取的布尔值.在最坏的情况下,您得到了错误的值,但由于异步执行无论如何都是虚假的影响.仅对于无法以原子方式读取或写入的数据,才需要进行同步.如果您需要同步,请不要使用Synchronize()它.

  • 没有必要MyThreadReady使用类似的变量,因为您可以使用它WaitForSingleObject()来查询线程的状态.通过MyThread.Handle作为第一个和0第二个参数给它,并检查结果是否是WAIT_OBJECT_0-如果让你的线程执行结束.

顺便说一句:不要使用该OnClose事件,请OnDestroy改用.前者不一定被调用,在这种情况下,您的线程可能会继续运行并使您的进程保持活动状态.


Rem*_*eau 5

让主线程为工作线程的 OnTerminate 事件分配一个处理程序。如果工作线程先完成,则处理程序可以向主线程发出信号以释放该线程。如果主线程先完成,它可以终止工作线程。例如:

procedure TMyThread.Execute;
begin
  ... Do some processing ...
end;

procedure TMainForm.Create;
begin
  MyThread := TMyThread.Create(True);
  MyThread.OnTerminate := ThreadFinished;
  MyThread.Resume; // or MyThread.Start; in D2010+
end;

const
  APPWM_FREE_THREAD = WM_APP+1;

procedure TMainForm.ThreadFinished(Sender: TObject);
begin
  PostMessage(Handle, APPWM_FREE_THREAD, 0, 0);
end;

procedure TMainForm.WndProc(var Message: TMessage);
begin
  if Message.Msg = APPWM_FREE_THREAD then
    StopWorkerThread
  else
    inherited;
end;

procedure TMainForm.StopWorkerThread;
begin
  if MyThread <> nil then
  begin
    MyThread.Terminate;
    MyThread.WaitFor;
    FreeAndNil(MyThread);
  end;
end;

procedure TMainForm.Close;
begin
  StopWorkerThread;
end;
Run Code Online (Sandbox Code Playgroud)

  • 不,我没有隐瞒任何事情。这是解决原始问题的一种更有效的方法,而且效果很好。工作线程根本不应该尝试直接释放自身。由于主线程是启动线程的线程,并且无论如何都需要管理线程,因此应该由主线程释放线程。TThread 有一个 OnTerminate 事件,专门用于在线程终止时通知其他代码,并完成与原始 `Synchronize(ThreadFinished)` 调用所做的完全相同的事情...... (2认同)
  • ... PostMessage() 技巧只是将线程的实际释放延迟几毫秒,因为它无法在 OnTerminate 事件本身内执行。但是工作线程在终止时仍然会被自动释放,它只是没有从线程本身内部释放,这是唯一的区别。 (2认同)