gpt4 book ai didi

multithreading - 如何在应用程序关闭时终止 Delphi 中的匿名线程?

转载 作者:行者123 更新时间:2023-12-03 14:42:31 24 4
gpt4 key购买 nike

我有一个 Delphi 应用程序,它在某些 TTimer.OnTimer 事件上生成 6 个匿名线程。

如果我通过标题栏中的 X 按钮关闭应用程序,则会引发地址 $C0000005 处的访问冲突,并且 FastMM 报告泄露的 TAnonymousThread 对象。

在 Delphi 中,使用 TThread.CreateAnonymousThread() 方法释放 OnTimer 事件中创建的匿名线程的最佳方法是什么?

对我有用的解决方案:

创建匿名线程的包装器,在释放它们时终止它们。

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;

这里是你如何调用它:

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;

无内存泄漏,正确关闭且易于使用。

最佳答案

如果您想维护并控制线程的生命周期,则必须将 FreeOnTerminate 设置为 False。否则,在线程开始执行后引用该线程是错误的。这是因为一旦它开始执行,您就没有现成的方法来知道它是否已被释放。

调用CreateAnonymousThread创建一个将 FreeOnTerminate 设置为 True 的线程。

The thread is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start.

因此,默认情况下,您无法控制线程的生命周期。不过,您可以在调用 Start 之前立即将 FreeOnTerminate 设置为 False。像这样:

MyThread := TThread.CreateAnonymousThread(MyProc);
MyThread.FreeOnTerminate := False;
MyThread.Start;

但是,我不确定我会这样做。 CreateAnonymousThread 的设计是线程在终止时自动释放。我认为我个人要么遵循预期的设计,要么派生我自己的 TThread 后代。

关于multithreading - 如何在应用程序关闭时终止 Delphi 中的匿名线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10401865/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com