1. Завершите и освободите поток, когда пользователь нажмет «Стоп», и создайте новый, когда он нажмет «Пуск».
Это конечно вариант, если накладные расходы минимальны.
3. Иметь свойство, которое является логическим значением, чтобы определить, приостановлен ли поток или нет. Код в Execute будет выполняться только в том случае, если это логическое значение равно false.
Вы могли бы сделать это, но вам пришлось бы регулярно проверять это логическое значение, и если оно установлено, то введите цикл ожидания до тех пор, пока оно не будет очищено или поток не получит сигнал о завершении.
Будет ли установка логического свойства для объекта TThread из основной формы потокобезопасным?
Это так же потокобезопасно, как вызов TThread.Terminate()
, который просто устанавливает логическое свойство TThread.Terminated
.
Какой из этих вариантов или какая-либо лучшая альтернатива мне следует выбрать?
Я использую вариант № 4 - использование сигнальных событий вместо логических. Например:
type
TMyThread = class(TThread)
private
FRunEvent, FTermEvent: TEvent;
FWaitEvents: THandleObjectArray;
procedure CheckPause;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Pause;
procedure Unpause;
end;
constructor TMyThread.Create;
begin
inherited Create(False);
FRunEvent := TEvent.Create(nil, True, True, '');
FTermEvent := TEvent.Create(nil, True, False, '');
SetLength(FWaitEvents, 2);
FWaitEvents[0] := FRunEvent;
FWaitEvents[1] := FTermEvent;
end;
destructor TMyThread.Destroy;
begin
FRunEvent.Free;
FTermEvent.Free;
inherited;
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
// do some work...
CheckPause;
// do some more work...
CheckPause;
// do some more work...
CheckPause;
//...
end;
end;
procedure TMyThread.TerminatedSet;
begin
FTermEvent.SetEvent;
end;
procedure TMyThread.CheckPause;
var
SignaledEvent: THandleObject;
begin
while not Terminated do
begin
case TEvent.WaitForMultiple(FWaitEvents, INFINITE, False, SignaledEvent) of
wrSignaled: begin
if SignaledEvent = FRunEvent then Exit;
Break;
end;
wrIOCompletion: begin
// retry
end;
wrError: begin
RaiseLastOSError;
end;
end;
SysUtils.Abort;
end;
procedure TMyThread.Pause;
begin
FRunEvent.ResetEvent;
end;
procedure TMyThread.Unpause;
begin
FRunEvent.SetEvent;
end;
person
Remy Lebeau
schedule
22.07.2016