问题
I've created an IOmniTaskControl using a TOmniWorker, so that I can periodically run chunks of code an a specific thread. So I'll be calling Invoke as needed on this IOmniTaskControl. When I do so, I will sometimes need to wait for the execution associated with that work to complete.
I tried calling WaitFor(INFINITE) on the IOmniTaskControl after the Invoke, but it hangs. I debugged and could see the method on the Invoke call completed. Am I misunderstanding the use of WaitFor with IOmniTaskControl when used with a TOmniWorker?
Edit: I edited up the test_43_InvokeAnonymous project in the test folder and I see the same behavior:
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;
With the above code, the task.WaitFor(INFINITE);
hangs.
回答1:
WaitFor
waits for the task to finish execution but as nobody told the task to terminate, it will wait forever.
Scheduling a background operation and then waiting for it more or less defeats the purpose of a background execution. It is better to schedule a background task and then send a notification back to the main thread when the task is finished. Use any variation of OnMessage (in the main thread) and Task.Comm.Send (in the worker).
Even better way would be to use Parallel.Future, which encapsulates exactly what you want to do.
If you really have to wait on the Invoke
to complete, you can create a waitable value before the Invoke
, signal it in the code executed by the Invoke
and wait for it in the code that called the Invoke
.
来源:https://stackoverflow.com/questions/36047891/waiting-for-invoke-to-finish-when-using-iomnitaskcontrol-tomniworker