четверг, 30 сентября 2010 г.

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

Очереди задач

Одной из возможностей OTL являются очереди. Что они собой представляют? Допустим Вам нужно запустить несколько фоновых задач, но в определенном порядке. Например, вы работаете с некоторым массивом данных. Первый поток, заполняет данный массив некоторыми значениями. Второй поток должен переслать весь массив данных, например в Интернет. Если Вы запустите сразу две задачи, то у вас будет путаница, например первый поток, еще не успеет заполнить массив, а второй отправит неполные данные.
Тут нужна синхронизация – скажете Вы. И будите правы. Правда, в нашем случае синхронизация будет заключаться в том, что бы второй поток (отправляющий данные) должен дождаться окончания работы первого (формирующий данные). Можно конечно используя TOmniEventMonitor следить за завершением первой задачи и запускать вторую по окончании первой, но это скажем так, не очень красиво, хотя и будет работать. Однако OTL предоставляет более красивое решение – так называемые очереди задач. При создании задачи ее можно поставить в очередь, которая будет выполняться последовательно друг за другом. То есть, поставив в очередь вторую задачу, Вы будите, уверены, что она не будет запущена на выполнения до тех пор, пока не завершится первая. Причем задачи можно создать будет одновременно. OTL сама возьмет на себя заботы по запуску и контролю задач в очереди. Интересно? не правда ли? Итак, приступим к разбору. Откроем демонстрационный пример: tests\16_ChainTo и рассмотрим реализацию
test_16_ChainTo.pas   Постановка задач в очередь
procedure TfrmTestChainTo.btnStartTasksClick(Sender: TObject);
var
  task1: IOmniTaskControl;
  task2: IOmniTaskControl;
  task3: IOmniTaskControl;
  taskA: IOmniTaskControl;
begin
  lbLog.Clear;
  task3 := CreateTask(BgTask, '3').MonitorWith(OmniTED);
  task2 := CreateTask(BgTask, '2').MonitorWith(OmniTED).ChainTo(task3);
  task1 := CreateTask(BgTask, '1').MonitorWith(OmniTED).ChainTo(task2);

  taskA := CreateTask(BgTask, 'A').MonitorWith(OmniTED).ChainTo(
           CreateTask(BgTask, 'B').MonitorWith(OmniTED).ChainTo(
           CreateTask(BgTask, 'C').MonitorWith(OmniTED)));
  task1.Run; taskA.Run;
end;

Итак, для постановки задачи в очередь служит метод ChainTo интерфейса IOmniTaskControl. Данный метод ставит созданную задачу перед задачей указанной в параметре task. Рассмотрим работу на примере задач 1,2,3. Сначала создается задача 3, после чего создается задача 2 и ставится в очередь перед задачей 3. Далее создается задача 1 и ставится в очередь перед задачей 2 и 3 соответственно. После чего task1.Run запускает первую задачу на выполнение, после выполнения задачи запускается вторая и соответственно после завершения второй задачи – третья.
Так как функция  ChainTo описана в интерфейсе
    function  ChainTo(const task: IOmniTaskControl;
                      ignoreErrors: boolean = false): IOmniTaskControl;
как возвращающая интерфейс IOmniTaskControl то возможна следующая конструкция кода, которая показана на примере taskA. Создаем задачу “А” и сразу же ставим ее перед задачей “B”. Далее “B” ставим в очередь перед “C”. После чего запускаем taskA.Run  на выполнение. Соответственно задачи выполняются в порядке A-B-C.

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

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