如何终止匿名线程在Delphi中的应用程序关闭? [英] How to terminate anonymous threads in Delphi on application close?
问题描述
我有一个Delphi应用程序,在一些TTimer.OnTimer事件上产生6个匿名线程。
如果我从标题栏中的X按钮关闭应用程序访问违例地址$ C0000005被提升,并且FastMM报告泄漏了TAnonymousThread对象。
哪些是使用TThread.CreateAnonymousThread()方法在OnTimer事件中创建的Delphi中释放匿名线程的最佳方式? / p>
解决方案对我有用:
创建一个匿名线程的包装器,在被释放时终止它们
type
TAnonumousThreadPool = class sealed(TObject)
strict private
FThreadList:TThreadList ;
程序TerminateRunningThreads;
procedure AnonumousThreadTerminate(Sender:TObject);
public
析构函数Destroy;覆盖最后;
程序启动(const Procs:TProc数组);
结束
{TAnonumousThreadPool}
程序TAnonumousThreadPool.Start(const Procs:TProc数组);
var
T:TThread
n:整数;
begin
TerminateRunningThreads;
FThreadList:= TThreadList.Create;
FThreadList.Duplicates:= TDuplicates.dupError;
为n:=低(Procs)到高(Procs)do
begin
T:= TThread.CreateAnonymousThread(Procs [n]);
TThread.NameThreadForDebugging(AnsiString('Test thread N:'+ IntToStr(n)+'TID:'),T.ThreadID);
T.OnTerminate:= AnonumousThreadTerminate;
T.FreeOnTerminate:= true;
FThreadList.LockList;
try
FThreadList.Add(T);
finally
FThreadList.UnlockList;
结束
T.Start;
结束
结束
procedure TAnonumousThreadPool.AnonumousThreadTerminate(Sender:TObject);
begin
FThreadList.LockList;
try
FThreadList.Remove((Sender as TThread));
finally
FThreadList.UnlockList;
结束
结束
程序TAnonumousThreadPool.TerminateRunningThreads;
var
L:TList;
T:TThread;
begin
如果没有分配(FThreadList)然后
退出;
L:= FThreadList.LockList;
尝试
,而L.Count> 0 do
begin
T:= TThread(L [0]);
T.OnTerminate:= nil;
L.Remove(L [0]);
T.FreeOnTerminate:= False;
T.Terminate;
T.Free;
结束
finally
FThreadList.UnlockList;
结束
FThreadList.Free;
结束
析构函数TAnonumousThreadPool.Destroy;
begin
TerminateRunningThreads;
继承;
结束
结束这里是如何调用它:
procedure TForm1.Button1Click(Sender:TObject);
begin
FAnonymousThreadPool.Start([//要执行的程序数组
procedure {anonymous1}()
var
Http:THttpClient;
begin
Http:= THttpClient.Create;
try
Http.CancelledCallback:= function:Boolean
begin
结果:= TThread.CurrentThread.CheckTerminated;
end ;
Http.GetFile('http://mtgstudio.com/Screenshots/shot1.png','c:\1.jpg');
finally
Http.Free;
end;
end,
procedure {anonymous2}()
var
Http:THttpClient;
begin
Http:= THttpClient.Create;
try
Http.CancelledCallback:= function:Boolean
begin
结果:= TThread.CurrentThread.CheckTerminated;
end;
Http .GetFile('http://mtgstudio.com/Screenshots/shot2.png','c:\2.jpg');
finally
Http.Free;
end;
结束
]);
结束
没有内存泄漏,正常关机和易于使用。
如果要维护并对线程的生命周期进行控制,则必须将 FreeOnTerminate
设置为 False
。否则,在线程开始执行后引用线程是一个错误。这是因为一旦它开始执行,你没有准备好的方法来知道它是否被释放。
调用 CreateAnonymousThread
创建一个 FreeOnTerminate
设置为 True
。
线程也被标记为FreeOnTerminate,所以在调用Start后不应该触摸返回的实例。
所以,但默认情况下,你无法对线程的生命周期进行控制。但是,您可以在调用开始之前将
。像这样: FreeOnTerminate
设置为 False
开始
MyThread:= TThread.CreateAnonymousThread(MyProc);
MyThread.FreeOnTerminate:= False;
MyThread.Start;
但是,我不知道我会这样做。 CreateAnonymousThread
的设计是线程在终止后自动释放。我想我个人会按照预期的设计,或者派生我自己的 TThread
descendent。
I have a Delphi application which spawns 6 anonymous threads upon some TTimer.OnTimer event.
If I close the application from the X button in titlebar Access Violation at address $C0000005 is raised and FastMM reports leaked TAnonymousThread objects.
Which is the best way to free anonymous threads in Delphi created within OnTimer event with TThread.CreateAnonymousThread() method?
SOLUTION which worked for me:
Created a wrapper of the anonymous threads which terminates them upon being Free-ed.
type
TAnonumousThreadPool = class sealed(TObject)
strict private
FThreadList: TThreadList;
procedure TerminateRunningThreads;
procedure AnonumousThreadTerminate(Sender: TObject);
public
destructor Destroy; override; final;
procedure Start(const Procs: array of TProc);
end;
{ TAnonumousThreadPool }
procedure TAnonumousThreadPool.Start(const Procs: array of TProc);
var
T: TThread;
n: Integer;
begin
TerminateRunningThreads;
FThreadList := TThreadList.Create;
FThreadList.Duplicates := TDuplicates.dupError;
for n := Low(Procs) to High(Procs) do
begin
T := TThread.CreateAnonymousThread(Procs[n]);
TThread.NameThreadForDebugging(AnsiString('Test thread N:' + IntToStr(n) + ' TID:'), T.ThreadID);
T.OnTerminate := AnonumousThreadTerminate;
T.FreeOnTerminate := true;
FThreadList.LockList;
try
FThreadList.Add(T);
finally
FThreadList.UnlockList;
end;
T.Start;
end;
end;
procedure TAnonumousThreadPool.AnonumousThreadTerminate(Sender: TObject);
begin
FThreadList.LockList;
try
FThreadList.Remove((Sender as TThread));
finally
FThreadList.UnlockList;
end;
end;
procedure TAnonumousThreadPool.TerminateRunningThreads;
var
L: TList;
T: TThread;
begin
if not Assigned(FThreadList) then
Exit;
L := FThreadList.LockList;
try
while L.Count > 0 do
begin
T := TThread(L[0]);
T.OnTerminate := nil;
L.Remove(L[0]);
T.FreeOnTerminate := False;
T.Terminate;
T.Free;
end;
finally
FThreadList.UnlockList;
end;
FThreadList.Free;
end;
destructor TAnonumousThreadPool.Destroy;
begin
TerminateRunningThreads;
inherited;
end;
End here is how you can call it:
procedure TForm1.Button1Click(Sender: TObject);
begin
FAnonymousThreadPool.Start([ // array of procedures to execute
procedure{anonymous1}()
var
Http: THttpClient;
begin
Http := THttpClient.Create;
try
Http.CancelledCallback := function: Boolean
begin
Result := TThread.CurrentThread.CheckTerminated;
end;
Http.GetFile('http://mtgstudio.com/Screenshots/shot1.png', 'c:\1.jpg');
finally
Http.Free;
end;
end,
procedure{anonymous2}()
var
Http: THttpClient;
begin
Http := THttpClient.Create;
try
Http.CancelledCallback := function: Boolean
begin
Result := TThread.CurrentThread.CheckTerminated;
end;
Http.GetFile('http://mtgstudio.com/Screenshots/shot2.png', 'c:\2.jpg');
finally
Http.Free;
end;
end
]);
end;
No memory leaks, proper shutdown and easy to use.
If you want to maintain and exert control over a thread's lifetimes then it must have FreeOnTerminate
set to False
. Otherwise it is an error to refer to the thread after it has started executing. That's because once it starts executing, you've no ready way to know whether or not it has been freed.
The call to CreateAnonymousThread
creates a thread with FreeOnTerminate
set to True
.
The thread is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start.
And so, but default, you are in no position to exert control over the thread's lifetime. However, you could set FreeOnTerminate
to False
immediately before calling Start
. Like this:
MyThread := TThread.CreateAnonymousThread(MyProc);
MyThread.FreeOnTerminate := False;
MyThread.Start;
However, I'm not sure I would do that. The design of CreateAnonymousThread
is that the thread is automatically freed upon termination. I think I personally would either follow the intended design, or derive my own TThread
descendent.
这篇关于如何终止匿名线程在Delphi中的应用程序关闭?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!