среда, 29 сентября 2010 г.

Использование OmniThread Libray (OTL) для создания многопоточных приложений - 8

Завершение фоновых задач по событию.

Одной из интересных особенностей библиотеки OTL в плане управления временем жизни фоновой задачи является  - завершение фоновой задачи по событию. Как вы знаете фоновую задачу можно завершить, используя метод Terminate. Однако есть еще один способ завершения фоновой задачи – способ завершения по событию. Для этого используется метод TerminateWhen с  объектом IOmniCancellationToken.
Идея метода состоит в том, что бы использовать одно событие  для остановки множества задач сразу. Рассмотрим использование TerminateWhen на демонстрационном примере tests\14_TerminateWhen.
test_14_TerminateWhen.pas   Создание фоновых задач
TfrmTestTerminateWhen = class(TForm)
.  .  .
  strict private
    FCounter  : IOmniCounter;
    FTerminate: IOmniCancellationToken;
.  .  .
procedure TfrmTestTerminateWhen.btnStartTasksClick(Sender: TObject);
var
  i: integer;
begin
  if assigned(FCounter) and (FCounter.Value > 0) then
    btnStopTasksClick(Sender);
  FCounter := CreateCounter(10);  // счетчик
  FTerminate := CreateOmniCancellationToken;  //сигнал остановки
  for i := 1 to FCounter.Value do begin
    Log(Format('Task started: %d',
      [
     CreateTask(TMyWorker.Create()).
           TerminateWhen(FTerminate).
           WithCounter(FCounter).
           MonitorWith(OmniTED).
           Run.
           UniqueID
       ]));
  end;
end;

Рассмотрим код более подробно. В секции strict private мы описываем две интерфейсных переменных. Одна FCounter – ссылается на счетчик (поддерживающий интерфейс IOmniCounter). Вторая переменная FTerminate – ссылается на класс, реализующий сигнальное событие.
Далее в методе btnStartTasksClick мы создаем класс реализующий интерфейс счетчика с помощью функции CreateCounter и присваиваем счетчику значение равное 10. После чего связываем данный класс с переменной FCounter.
Так-же мы создаем класс “сигнала-остановки” с помощью CreateOmniCancellationToken и так-же связываем его с интерфейсной переменной. Функции CreateCounter и CreateOmniCancellationToken определены в модуле OtlCommon.pas.
Разберем подробнее, класс сигнального события TOmniCancellationToken (реализующего интерфейс IOmniCancellationToken). Данный класс реализует стандартный Windows-объект синхронизации Event, служащий для создания события и имеющий два сигнальных состояния – отмеченное или неотмеченное.
Интерфейс IOmniCancellationToken
  IOmniCancellationToken = interface ['{5946F4E8-45C0-4E44-96AB-DBE2BE66A701}']
    function  GetHandle: THandle;
  //
    procedure Clear;
    function  IsSignaled: boolean;
    procedure Signal;
    property Handle: THandle read GetHandle;
  end; { IOmniCancellationToken }

Далее мы создаем 10 фоновых задач и связываем их с помощью метода TerminateWhen с интерфейсом сигнального события. После чего запускаем фоновые задачи на выполнение.
Теперь если мы хотим завершить работу всех запущенных ранее потоков нам нужно выставить наш объект FTerminate в сигнальное состояние, используя метод Signal. После выставление сигнала, внутренний механизм OTL увидит, что пришел сигнал “завершения задачи” и начнет закрывать фоновые задачи.
test_14_TerminateWhen.pas   Завершение фоновых задач по событию
procedure TfrmTestTerminateWhen.btnStopTasksClick(Sender: TObject);
begin
  if not assigned(FTerminate) then
    Exit;
  FTerminate.Signal;  //Выставляем объект в сигнальное состояние
  while FCounter.Value > 0 do begin // ugly, I know
    Sleep(10);
    Application.ProcessMessages;
  end;
  Log('All stopped');
end;

Комментариев нет:

Отправить комментарий