Ожидание завершения 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
,