"Приостановка" потока со свойством

У меня есть объект TThread и я хочу иметь возможность запускать / останавливать поток с помощью кнопки на главной форме программы. Я искал способы сделать это, и до сих пор у меня есть следующие идеи:

  1. Завершите и освободите поток, когда пользователь нажмет кнопку "Стоп", и создайте новый, когда он нажмет "Пуск".
  2. Используйте сон, чтобы задержать поток (я не хочу этого делать)
  3. Имейте свойство, которое является логическим, чтобы определить, приостановлен ли поток или нет. Код в Execute произойдет только в том случае, если это логическое значение false.

Я склоняюсь к #3. Будет ли установка логического свойства для объекта TThread из главной формы поточно-ориентированным?

Какой из этих вариантов или лучшую альтернативу я должен выбрать? Я впервые использую темы, поэтому любая помощь приветствуется.

2 ответа

Решение

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;

Посмотрите вики для Delphi о запуске и остановке потоков здесь: http://docwiki.embarcadero.com/RADStudio/Berlin/en/Starting_and_Stopping_Threads

Это применимо еще к Delphi 7. Это может быть применимо и дальше, но я не могу подтвердить более ранние версии.

Другие вопросы по тегам