目前我正在使用额外的线程来完美地释放线程后的内存。 在你问之前。不,我不能使用FreeOnTerminate:= true因为我需要.waitfor。 我还需要FreeAndNil(),因为只有这样我才能使用Assigned()检查线程是否正在运行。示例代码。
procedure TForm1.Button1Click(Sender: TObject);
begin
SupervisorThread:= TSupervisorThread.Create(True);
SupervisorThread.FreeOnTerminate:=false; //MUST BE FALSE!
SupervisorThread.Priority := tpNormal;
SupervisorThread.Resume;
end;
procedure TSupervisorThread.Execute;
begin
CleaningThread:= TCleaningThread.Create(True);
CleaningThread.FreeOnTerminate:=true;
CleaningThread.Priority := tpNormal;
CleaningThread.Resume;
//some loops here
end;
procedure TCleaningThread.Execute;
begin
if Assigned(SupervisorThread)=true then
begin
SupervisorThread.WaitFor;
FreeAndNil(SupervisorThread);
end;
end;
procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Assigned(SupervisorThread)=false then CanClose:=true
else
begin
CanClose:=false;
ShowMessage('Cannot close form because SiupervisorThread is still working');
end;
end;
答案 0 :(得分:4)
使用TThread.OnTerminate
事件:
private
procedure DoTerminateEvent(Sender: TObject);
var
isRunning: Boolean;
procedure TForm2.DoTerminateEvent(Sender: TObject);
begin
isRunning := False;
end;
procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if (isRunning) then
begin
CanClose := false;
ShowMessage('Cannot close form because SupervisorThread is still working')
end else
CanClose := true;
end;
创建线程时设置OnTerminate
处理程序:
SupervisorThread := TSupervisorThread.Create(True);
...
SupervisorThread.OnTerminate := DoTerminateEvent;
SupervisorThread.Resume;
或者,将它作为参数传递给Thread的构造函数:
TSupervisorThread = class(TThread)
public
constructor Create(OnTerminatEvent: TNotifyEvent);
end;
procedure TThreadCustom.Create(OnTerminateEvent: TNotifyEvent);
begin
inherited Create(True);
OnTerminate := OnTerminateEvent;
end;
SupervisorThread := TSupervisorThread.Create(DoTerminateEvent);
答案 1 :(得分:1)
您可以使用TThread.OnTerminate
事件来检测线程何时完成运行,例如:
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(SupervisorThread) then
begin
SupervisorThread:= TSupervisorThread.Create(True);
SupervisorThread.FreeOnTerminate := False;
SupervisorThread.Priority := tpNormal;
SupervisorThread.OnTerminate := SupervisorThreadTerminated;
SupervisorThread.Resume;
end;
end;
procedure TForm1.SupervisorThreadTerminated(Sender: TObject);
begin
SupervisorThread := nil;
end;
但是,这会产生一些问题。它会创建一个竞争条件,因为清理线程作用于SupervisorThread
指针,当清洁线程仍在运行时,该指针可能随时消失。它会造成内存泄漏,因为您仍然需要在SupervisorThread
对象终止后释放它,但您无法直接在OnTerminate
处理程序中执行此操作。
更好的解决方案根本不依赖于SupervisorThread
指针。
var
SupervisorTerminated: TEvent;
procedure TForm1.FormCreate(Sender: TObject);
begin
SupervisorTerminated := TEvent.Create(nil, True, True, '');
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if Assigned(SupervisorThread) then
begin
SupervisorThread.Terminate;
while SupervisorTerminated.WaitFor(1000) = wrTimeout do
CheckSynchronize;
end;
SupervisorTerminated.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(SupervisorThread) then
begin
SupervisorThread := TSupervisorThread.Create(True);
SupervisorThread.FreeOnTerminate := True;
SupervisorThread.Priority := tpNormal;
SupervisorThread.OnTerminate := SupervisorThreadTerminated;
SupervisorTerminated.ResetEvent;
SupervisorThread.Resume;
end;
end;
procedure TForm1.SupervisorThreadTerminated(Sender: TObject);
begin
SupervisorThread := nil;
SupervisorTerminated.SetEvent;
end;
procedure TCleaningThread.Execute;
begin
SupervisorTerminated.WaitFor(INFINITE);
end;
procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := (SupervisorTerminated.WaitFor(0) = wrSignaled);
if not CanClose then
ShowMessage('Cannot close form because Supervisor Thread is still working');
end;