Ожидание завершения Invoke при использовании IOmniTaskControl/TOmniWorker

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

Я попытался вызвать WaitFor(INFINITE) на IOmniTaskControl после Invoke, но он зависает. Я отладил и увидел, что метод вызова Invoke завершен. Я неправильно понимаю использование WaitFor с IOmniTaskControl при использовании с TOmniWorker?

Изменить: я отредактировал проект test_43_InvokeAnonymous в папке test, и я вижу то же поведение:

procedure TfrmInvokeAnonymousDemo.btnInvokeClick(Sender: TObject);
var
  formThreadID: DWORD;
  task        : IOmniTaskControl;
begin
  formThreadID := GetCurrentThreadID;
  if Sender = btnInvoke then
    task := FTask
  else
    task := FMonitoredTask;

  task.Invoke(
    procedure (const task: IOmniTask)
    var
      taskThreadID: DWORD;
    begin
      // this will execute in the context of the worker thread
      taskThreadID := GetCurrentThreadID;
      Sleep(2000);
//      task.Invoke(
//        procedure
//        begin
//          // this will execute in the context of the main thread
//          frmInvokeAnonymousDemo.lbLog.Items.Add(Format(
//            'Current thread ID: %d, task thread ID: %d, ' +
//            ' form thread ID: %d',
//            [GetCurrentThreadID, taskThreadID, formThreadID]));
//        end
//      );
    end
  );

  task.WaitFor(INFINITE);
  frmInvokeAnonymousDemo.lbLog.Items.Add('Done waiting.');
end;

С приведенным выше кодом, task.WaitFor(INFINITE); висит.

1 ответ

Решение

WaitFor ожидает завершения задачи, но поскольку никто не велел завершить задачу, она будет ждать вечно.

Планирование фоновой операции, а затем ее ожидание более или менее отрицательно сказывается на цели фонового выполнения. Лучше запланировать фоновую задачу, а затем отправить уведомление обратно в основной поток, когда задача будет завершена. Используйте любой вариант OnMessage (в основной ветке) и Task.Comm.Send (в рабочем).

Еще лучше было бы использовать Parallel.Future, который инкапсулирует именно то, что вы хотите сделать.

Если вам действительно нужно ждать на Invoke чтобы завершить, вы можете создать ожидаемое значение до Invoke, сообщите об этом в коде, выполняемом Invoke и ждать его в коде, который называется Invoke,

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