Самостоятельная приостановка потока в Delphi, когда он не нужен и безопасно возобновляется

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

что я хотел бы знать, есть ли лучший способ, чтобы приостановить поток, когда он не нужен?

у нас есть класс Delphi, который мы использовали в течение многих лет, который в основном является очередью FIFO, связанной с потоковым процессом. Очередь принимает объект данных на основной поток, и если поток приостановлен, он возобновит его.

как часть процесса выполнения потока объект выскакивает из очереди и обрабатывается в потоке. Обычно это делается для поиска базы данных.

в конце процесса свойство объекта обновляется и помечается как доступное основному потоку или передается в другую очередь. Последний (ну, это действительно первый) шаг процесса выполнения-проверить, есть ли еще какие-либо элементы в очередь. Если оно существует, то продолжается, иначе оно приостанавливается.

They-единственное действие приостановки внутри цикла выполнения, когда оно завершено, и единственное возобновление во время обычных операций вызывается, когда новый элемент помещается в очередь. Исключение - когда класс queue завершается.

функция resume выглядит примерно так.

process TthrdQueue.MyResume();
  begin
    if Suspended then begin
      Sleep(1); //Allow thread to suspend if it is in the process of suspending
      Resume();
    end;
  end;

выполнение похоже на это

process TthrdQueue.Execute();
  var
    Obj : TMyObject;
  begin
    inherited;
    FreeOnTerminate := true;
    while not terminated do begin
      if not Queue.Empty then begin
        Obj :=  Pop();
        MyProcess(Obj);  //Do work
        Obj.Ready := true;
      end
      else
        Suspend();  // No more Work
    end;   //Queue clean up in Destructor
  end;  

процедура нажатия Tthrdqueue вызывает MyResume после добавления другого объекта в стек. MyResume вызывает Resume, только если поток приостановлен.

при выключении мы устанавливаем terminate в true и вызываем MyResume, если он приостановлен.

3 ответов


Я бы рекомендовал следующую реализацию TthrdQueue:

type
  TthrdQueue = class(TThread)
  private
    FEvent: THandle;
  protected
    procedure Execute; override;
  public
    procedure MyResume;
  end;

implementation

procedure TthrdQueue.MyResume;
begin
  SetEvent(FEvent);
end;

procedure TthrdQueue.Execute;
begin
  FEvent:= CreateEvent(nil,
                       False,    // auto reset
                       False,    // initial state = not signaled
                       nil);
  FreeOnTerminate := true;
  try
    while not Terminated do begin
      if not Queue.Empty then begin
        Obj :=  Pop();
        MyProcess(Obj);  //Do work
        Obj.Ready := true;
      end
      else
        WaitForSingleObject(FEvent, INFINITE);  // No more Work
    end;
  finally
    CloseHandle(FEvent);
  end;
end;

вместо того, чтобы приостанавливать поток, сделайте его спящим. Сделайте его блокируемым на какой-то ожидаемой ручке, и когда ручка станет сигнализированной, поток проснется.

у вас есть много вариантов для объектов waitable, включая события, объекты мьютекса, семафоры, очереди сообщений, каналы.

Предположим, вы решили использовать это событие. Сделайте это событием автоматического сброса. Когда очередь пуста, вызовите событие WaitFor метод. Когда что-то еще заполняет очередь или хочет выйти, имейте это вызовите событие SetEvent метод.

Я предпочитаю использовать очередь сообщений ОС. Я бы заменил ваш объект очереди сообщениями. Затем напишите стандарт GetMessage петли. Когда очередь пуста, она автоматически блокирует ожидание нового сообщения. Превратите запрос о прекращении в еще одно сообщение. (The TThread.Terminate метод просто не очень полезная функция, когда вы начинаете делать что-нибудь интересное с темы, потому что он не виртуальный.)


существует библиотека, позволяющая реализовать очередь производитель-потребитель в Delphi с использованием переменных условий. Этот сценарий фактически является обсуждаемым примером.

классический пример состояния переменные-это производитель / потребитель проблема. Один или несколько потоков производители производят изделия и добавляют их в очередь. Потребители (другие темы) уничтожьте детали путем извлекать произведенный элементы из очереди.