在给定示例中,我在调用AThread.Free.
program Project44;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, Windows;
type
TMyException = class(Exception);
var
AThread: TThread;
begin
AThread := TThread.Create(True);
try
AThread.FreeOnTerminate := True;
//I want to do some things here before starting the thread
//During the setup phase some exception might occur, this exception is for simulating purpouses
raise TMyException.Create('exception');
except
AThread.Free; //Another exception here
end;
end.
我有两个问题:
在给定的示例中,如何释放AThread
TThread
个实例?
我不明白为什么TThread.Destroy
在销毁之前调用Resume
。有什么意义呢?
答案 0 :(得分:15)
您无法在线程实例上将FreeOnTerminate
设置为True
和调用Free
。你必须做一个或另一个,但不是两个。因为它代表你的代码破坏线程两次。你必须永远不要销毁一个对象两次,当然,当析构函数第二次运行时,会发生错误。
这里发生的事情是,由于您创建了线程暂停,因此在您明确释放线程之前不会发生任何事情。当你这样做时,析构函数恢复线程,等待它完成。然后,这会导致再次调用Free
,因为您将FreeOnTerminate
设置为True
。第二次调用Free
会关闭句柄。然后返回线程proc并调用ExitThread
。这会失败,因为线程的句柄已经关闭。
正如Martin在评论中指出的那样,您不能直接创建TThread
,因为TThread.Execute
方法是抽象的。此外,您不应使用已弃用的Resume
。使用Start
开始执行挂起的线程。
我个人不喜欢使用FreeOnTerminate
。使用此功能会导致线程在创建它的其他线程上被销毁。当您想要忘记实例引用时,通常会使用它。这样就可以确定在进程终止时线程是否已被销毁,或者在进程终止期间是否终止并释放自己。
如果您必须使用FreeOnTerminate
,则需要确保在将Free
设置为FreeOnTerminate
后不要致电True
。因此,显而易见的解决方案是在调用FreeOnTerminate
之后立即将True
设置为Start
,然后忘记线程实例。如果您在准备开始之前有任何例外,那么您可以放心地释放该线程,因为那时FreeOnTerminate
仍然是False
。
Thread := TMyThread.Create(True);
Try
//initialise thread object
Except
Thread.Free;
raise;
End;
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
更优雅的方法是将所有初始化移动到TMyThread
构造函数中。然后代码看起来像这样:
Thread := TMyThread.Create(True);
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
答案 1 :(得分:5)
你的情况非常复杂。
首先,你实际上没有释放被挂起的线程;一个线程在析构函数中恢复:
begin
Terminate;
if FCreateSuspended then
Resume;
WaitFor;
end;
由于在Terminate
之前调用Resume
,Execute
方法永远不会运行,并且线程在恢复后立即终止:
try
if not Thread.Terminated then
try
Thread.Execute;
except
Thread.FFatalException := AcquireExceptionObject;
end;
finally
Result := Thread.FReturnValue;
FreeThread := Thread.FFreeOnTerminate;
Thread.DoTerminate;
Thread.FFinished := True;
SignalSyncEvent;
if FreeThread then Thread.Free;
现在看看最后一行 - 你从析构函数本身调用析构函数(Thread.Free
)!
太棒了!
回答你的问题:
FreeOnTerminate:= True
; DoTerminate
方法)应该在线程上下文中执行
线程终止。您可以向QC发送功能请求:将FFreeOnTerminate:= False
添加到TThread.Destroy
实施:
destructor TThread.Destroy;
begin
FFreeOnTerminate:= False;
// everything else is the same
..
end;
这应该阻止递归的析构函数调用并使代码有效。