Как приостановить поток?

Я хочу что-нибудь нарисовать. Поскольку графический интерфейс зависает, я хочу рисовать в потоке. Но иногда хочется поставить рисование на паузу (на минуты).

В документации Delphi говорится, что Suspend/resume устарели, но не сообщается, какие функции их заменяют.

Приостановка и возобновление устарели. Sleep и SpinWait явно неуместны. Я поражен, увидев, что Delphi не предлагает такого базового свойства/функции.

Итак, как мне приостановить/возобновить поток?


person Z80    schedule 29.05.2017    source источник
comment
Вы устанавливаете флаг, который ваш поток регулярно проверяет. Затем он рисует или не рисует, в зависимости от значения флага.   -  person David Heffernan    schedule 29.05.2017
comment
Используйте событие и WaitForSingleObject...   -  person whosrdaddy    schedule 29.05.2017
comment
@DavidHeffernan - хорошо. и что мне использовать, чтобы приостановить поток, когда флаг «DoNotDraw»? THread.Sleep(100) - хорошая идея??   -  person Z80    schedule 29.05.2017
comment
Неа. Спать — это почти всегда плохая идея. Вместо этого вы можете дождаться события. Сделайте это вместо простого флага. Итак, в вашем цикле рисования дождитесь сигнала события. В основном потоке сбросьте событие, когда вы хотите приостановить рисование. Установите его снова, если хотите возобновить рисование.   -  person David Heffernan    schedule 29.05.2017
comment
@whosrdaddy - Просто примечание :) При поиске документации по WaitForSingleObject я нашел это: marc.durdin.net/2012/08/   -  person Z80    schedule 29.05.2017
comment
Вы делаете то, что мы уже сказали. Дождитесь события.   -  person David Heffernan    schedule 29.05.2017
comment
Использование WaitForSingleObject нормально, если вы делаете это правильно   -  person David Heffernan    schedule 29.05.2017


Ответы (1)


Вам может понадобиться fPaused/fEvent защита через критическую секцию. Это зависит от вашей конкретной реализации.

interface

uses
  Classes, SyncObjs;

type
  TMyThread = class(TThread)
  private
    fEvent: TEvent;
    fPaused: Boolean;
    procedure SetPaused(const Value: Boolean);
  protected
    procedure Execute; override;
  public
    constructor Create(const aPaused: Boolean = false);
    destructor Destroy; override;

    property Paused: Boolean read fPaused write SetPaused;
  end;

implementation

constructor TMyThread.Create(const aPaused: Boolean = false);
begin
  fPaused := aPaused;
  fEvent := TEvent.Create(nil, true, not fPaused, '');
  inherited Create(false);
end;

destructor TMyThread.Destroy;
begin
  Terminate;
  fEvent.SetEvent;
  WaitFor;
  fEvent.Free;
  inherited;
end;

procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    fEvent.WaitFor(INFINITE);
    // todo: your drawings here
  end;
end;

procedure TMyThread.SetPaused(const Value: Boolean);
begin
  if (not Terminated) and (fPaused <> Value) then
  begin
    fPaused := Value;
    if fPaused then
      fEvent.ResetEvent else
      fEvent.SetEvent;
  end;
end;
person Peter Kostov    schedule 29.05.2017
comment
Разве унаследованное от конструктора не должно быть в начале, а не в конце кода? - person Alberto Miola; 29.05.2017
comment
Это распространенный шаблон, изученный до того, как Delphi 6 исправила конструктор для TThread, чтобы отложить фактическое создание потока до AfterConstruction. С тех пор не было необходимости писать это, как указано выше. - person David Heffernan; 29.05.2017
comment
@DavidHeffernan: Простите, что я не знаю, но что из вышеперечисленного не было необходимо с D6? - person Alex James; 29.05.2017
comment
@AlexJames Вызов унаследованного конструктора в конце производного конструктора - person David Heffernan; 29.05.2017