在使用Delphi for iOS下进行ARC管理时,如何正确终止线程?
请参考以下简单示例:
TMyThread = class(TThread)
protected
procedure Execute; override;
public
destructor Destroy; override;
end;
TForm2 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
FThread: TMyThread;
public
end;
{ TMyThread }
destructor TMyThread.Destroy;
begin
ShowMessage('Destroy');
inherited Destroy;
end;
procedure TMyThread.Execute;
begin
Sleep(5000);
end;
{ TForm2 }
procedure TForm2.Button1Click(Sender: TObject);
begin
FThread := TMyThread.Create(TRUE);
FThread.FreeOnTerminate := TRUE;
FThread.Start;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
ShowMessage(FThread.RefCount.ToString);
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
FThread := nil;
end;
好的,按下Button1将会生成一个线程。线程启动后,如果您点击Button2,它将显示一个RefCount值为3!!其中1是对我的FThread变量的引用,还有2个TThread内部创建的附加引用... 我已经深入研究了源代码,并发现RefCount在这里增加:
constructor TThread.Create(CreateSuspended: Boolean);
ErrCode := BeginThread(nil, @ThreadProc, Pointer(Self), FThreadID);
if ErrCode <> 0 then
raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(ErrCode)]);
{$ENDIF POSIX}
还有这里:
function ThreadProc(Thread: TThread): Integer;
var
FreeThread: Boolean;
begin
TThread.FCurrentThread := Thread;
嗯... 在线程结束后(在我的情况下,5秒钟后),RefCount将会减少到2(因为我已将FreeOnTerminate设置为TRUE,但如果我没有设置FreeOnTerminate为TRUE,则RefCount仍将是3)。
看到问题了吗?如果调用FThread := nil,那么RefCount应该从2减少到1(或者在FreeOnTerminate = FALSE
的情况下从3减少到2),并且在线程下使用ARC时,线程永远不会被释放......
也许我错过了什么,因为我习惯于处理没有ARC的线程......那么我在这里错过了什么?或者是TThread在ARC下的实现中存在bug吗?
也许是TThread的定义问题。
private class threadvar
FCurrentThread: TThread;
应该是这样的
private class threadvar
[Weak] FCurrentThread: TThread;
FCurrentThread
从未被设置为nil
。我还注意到ThreadWrapper
将New
与FreeMem
配对使用,这显然是错误的。New
应该与Dispose
配对使用。而且,由于分配的对象包含对线程的引用,可能会导致内存泄漏。但是由于Self
被强制转换为Pointer
,所以应该是一个弱引用。我会将其简化为一个最小示例,并提交一个 QC 报告。 - David HeffernanThreadProc()
在线程运行结束后没有将TThread.FCurrentThread
设置为nil。这至少会导致一个悬空引用。但我不明白为什么引用计数会增加到3。BeginThread()
代码并没有做任何应该影响引用计数的事情。 - Remy Lebeau