Основываясь на нескольких вопросах здесь, в SO, я реализовал поток, который может быть убит пользователем до завершения его работы или если я его установлю для самостоятельного завершения через определенный промежуток времени.Delphi - потоки, остановленные пользователем или автоматически завершающиеся по истечении определенного периода времени
реализация Тема:
unit Unit2;
interface
uses SyncObjs
,classes
,System.SysUtils
,windows;
type
TMyThread = class(TThread)
private
FTerminateEvent: TEvent;
FTimerStart: Cardinal;
FTimerLimit: Cardinal;
FTimeout: Boolean;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create(ACreateSuspended: Boolean; Timeout: Cardinal); overload;
destructor Destroy; override;
end;
implementation
constructor TMyThread.Create(ACreateSuspended: Boolean; TimeOut: Cardinal);
begin
inherited Create(ACreateSuspended);
FTerminateEvent := TEvent.Create(nil, True, False, '');
FTimerStart:=GetTickCount;
FTimerLimit:=Timeout;
FTimeout:=True;
end;
destructor TMyThread.Destroy;
begin
OutputDebugString(PChar('destroy '+inttostr(Handle)));
inherited;
FTerminateEvent.Free;
end;
procedure TMyThread.TerminatedSet;
begin
FTerminateEvent.SetEvent;
end;
procedure TMyThread.Execute;
var
FTimerNow:Cardinal;
begin
FTimerNow:=GetTickCount;
while not(Terminated) and ((FTimerNow-FTimerStart)<FTimerLimit) do
begin
OutputDebugString(PChar('execute '+inttostr(Handle)));
FTerminateEvent.WaitFor(100);
FTimerNow:=GetTickCount;
end;
if (FTimerNow-FTimerStart) > FTimerLimit then
begin
self.Free;
end;
end;
end.
и как потоки создаются в главном блоке приложения
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs
,unit2, Vcl.StdCtrls
;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
t1,t2: TMyThread;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
//
if t1 = nil then
t1 := TMyThread.Create(false,10000)
else
if t2 = nil then
t2 := TMyThread.Create(False,10000);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
//
if t1 <> nil then
begin
t1.Free;
t1 := nil;
end
else
if t2 <> nil then
begin
t2.Free;
t2 := nil;
end;
end;
end.
То, что я хочу, это рабочий поток, который останавливается либо когда я убиваю его , либо через определенный промежуток времени. Проблема возникает, когда поток нуждается в самостоятельном завершении, потому что там я получаю утечки памяти, и мое событие не освобождается.
LE: настройка FreeOnTerminate
на True
приводит к нарушениям множественного доступа.
Неплохая идея вызвать Terminate на экземпляре потока, который является 'FreeOnTerminate'. Он может быть освобожден уже тайм-аутом. Кроме того, управление нулевой настройкой вообще не требуется. Просто создайте потоки из локальной переменной или без какой-либо переменной. –
Используйте флаг вместо этого, чтобы сообщить, когда поток завершил свое задание в событии 'OnTerminate'. –
@LURD Событие ['TThread.OnTerminate'] (http://docwiki.embarcadero.com/Libraries/en/System.Classes.TThread.OnTerminate) - это синхронизированный вызов внутри контекста MainThread. Если вы введете метод 'TForm1.Button2Click', у вас будет действительная ссылка в 't1' /' t2' или 'nil'. Таким образом, такой подход безопасен. –