我在我的程序中有一个主线程和一个单独的线程。如果独立线程在主线程之前完成,它应该自动释放自己。如果主线程首先完成,它应该释放单独的线程。
我知道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;发布于 2010-08-24 22:34:43
您可以将其简化为:
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;解释:
FreeOnTerminate,要么手动释放线程,但决不能同时使用这两种方法。线程执行的异步本质意味着您可能不会释放线程,或者(更糟糕的是)执行两次。在线程对象完成执行后将其保留不会有任何风险,在已经完成的线程上调用Terminate()也不会有风险。Synchronize()。MyThreadReady的变量,因为你可以使用WaitForSingleObject()查询线程的状态。将MyThread.Handle作为第一个参数传递给它,将0作为第二个参数传递给它,并检查结果是否为WAIT_OBJECT_0 -如果是的话,您的线程已经完成了执行。顺便说一句:不要使用OnClose事件,而要使用OnDestroy。前者不一定会被调用,在这种情况下,您的线程可能会继续运行并使您的进程保持活动状态。
发布于 2010-08-25 01:06:03
让主线程为辅助线程的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;发布于 2010-08-24 22:17:19
不,你的代码不好(尽管它可能在99.99%甚至100%的情况下都能工作)。如果您计划从主线程终止工作线程,不要将FreeOnTerminate设置为True (我看不出您试图通过将FreeOnTerminate设置为True在上面的代码中获得什么,这至少会使您的代码更难理解)。
终止工作线程的一个更重要的情况是,当工作线程处于等待状态时,您正在尝试关闭应用程序。如果你只是调用Terminate,线程将不会被唤醒,通常你应该使用额外的同步对象(通常是事件)来唤醒工作线程。
再说一句--没有必要
begin
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
end;如果您查看TThread.Destroy代码,它将调用Terminate和WaitFor,因此
MyThread.Free;足够了(至少在Delphi 2009中,手头没有Delphi 7源码可供检查)。
已更新
阅读mghie答案。考虑以下情况(在1个CPU系统上更好):
主线程正在执行
procedure TMainForm.Close;
begin
if not MyThreadReady then
begin
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
end;
end;它检查了MyThreadReady值(它是False),并被调度程序关闭。
现在调度器切换到工作线程;它执行
Synchronize(ThreadFinished);并强制调度器切换回主线程。主线程继续执行:
MyThread.Terminate; // no problem
MyThread.WaitFor; // ???
MyThread.Free;你能说一下WaitFor会发生什么吗?我不能(需要更深入地研究TThread源代码才能回答,但乍看起来像是死锁)。
你真正的错误是不同的东西-你写了一个不可靠的代码,并试图找出它是正确的还是错误的。这是一个糟糕的线程实践--你应该学会写一个可靠的代码。
至于资源-当TThread ( FreeOnTerminate = False)被终止时,剩下的资源只有Windows线程句柄(线程终止后它不会使用大量的Windows资源)和内存中的Delphi TThread对象。为了安全起见,这并不是很大的成本。
https://stackoverflow.com/questions/3557105
复制相似问题