Как прекратить анонимные потоки в Delphi при закрытии приложения?
у меня есть приложение Delphi, которое порождает 6 анонимных потоков на некотором TTimer.Событие OnTimer.
Если я закрою приложение от кнопки X в заголовке нарушение доступа по адресу $C0000005 поднимается и fastmm отчеты просочились TAnonymousThread объектов.
это лучший способ освободить анонимные потоки в Delphi, созданные в событии OnTimer с помощью TThread.CreateAnonymousThread() метод?
решение, которое работало для я:
создал оболочку анонимных потоков, которая завершает их при свободном редактировании.
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:.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:.jpg');
finally
Http.Free;
end;
end
]);
end;
отсутствие утечек памяти, правильное выключение и простота в использовании.
3 ответов
если вы хотите поддерживать и контролировать время жизни потока, то он должен иметь FreeOnTerminate
значение False
. В противном случае ссылка на поток после его запуска является ошибкой. Это потому, что как только он начнет выполняться, у вас нет готового способа узнать, был ли он освобожден.
вызов CreateAnonymousThread
создает поток с FreeOnTerminate
значение True
.
поток также отмечен как FreeOnTerminate, поэтому вы не следует прикасаться к возвращаемому экземпляру после вызова Start.
и так, но по умолчанию вы не в состоянии контролировать время жизни потока. Тем не менее, вы можете установить FreeOnTerminate
to False
непосредственно перед вызовом Start
. Вот так:
MyThread := TThread.CreateAnonymousThread(MyProc);
MyThread.FreeOnTerminate := False;
MyThread.Start;
однако я не уверен, что сделал бы это. Дизайн CreateAnonymousThread
является то, что поток автоматически освобождается после завершения. Я думаю, что лично я бы либо следовал намеченному дизайну, либо получил мой собственный TThread
descendent.
чтобы избежать ошибок с помощью CreateAnonymousThread
просто набор FreeOnTerminate
to False
прежде чем начать его.
таким образом, вы можете работать с потоком, как обычно, без каких-либо обходных путей.
вы можете прочитать документацию, которая говорит, что CreateAnonymousThread
автоматически FreeOnTerminate
to True
и это то, что вызывает ошибки при ссылке на поток.
Заставьте свои потоки следить за каким-то уведомлением извне. Это может быть событие, которое получает сигнал, сообщение, отправленное в окно, принадлежащее потоку, команда, отправленная через сокет, который слушает ваш поток, или любая другая форма связи, которую вы найдете.
Если вы определяете, что эта проблема заключается в том, что ваши потоки являются так называемыми "анонимными" потоками, то простой обходной путь-сделать их не анонимными потоками. Положите тело анонима функция в Execute
метод и передать любые захваченные переменные в класс thread через его конструктор.