使用 IOmniTaskControl/TOmniWorker 时等待调用完成
Waiting for Invoke to finish when using IOmniTaskControl/TOmniWorker
我已经使用 TOmniWorker 创建了一个 IOmniTaskControl,这样我就可以定期 运行 代码块到特定线程。因此,我将根据需要在此 IOmniTaskControl 上调用 Invoke。当我这样做时,有时我需要等待与该工作相关的执行完成。
我尝试在 Invoke 之后在 IOmniTaskControl 上调用 WaitFor(INFINITE),但它挂起。我进行了调试,可以看到 Invoke 调用上的方法已完成。当与 TOmniWorker 一起使用时,我是否误解了将 WaitFor 与 IOmniTaskControl 一起使用?
编辑:我编辑了测试文件夹中的 test_43_InvokeAnonymous 项目,我看到了相同的行为:
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);
挂起。
WaitFor
等待任务完成执行,但由于没有人告诉任务终止,它将永远等待。
安排后台操作然后等待它或多或少违背了后台执行的目的。最好安排一个后台任务,然后在任务完成时将通知发回主线程。使用 OnMessage
(in the main thread) and Task.Comm.Send
的任何变体(在 worker 中)。
更好的方法是使用 Parallel.Future
,它完全封装了您要执行的操作。
如果你真的需要等待 Invoke
完成,你可以在 Invoke
之前创建一个 waitable value,在 [=14= 执行的代码中通知它] 并在调用 Invoke
.
的代码中等待它
我已经使用 TOmniWorker 创建了一个 IOmniTaskControl,这样我就可以定期 运行 代码块到特定线程。因此,我将根据需要在此 IOmniTaskControl 上调用 Invoke。当我这样做时,有时我需要等待与该工作相关的执行完成。
我尝试在 Invoke 之后在 IOmniTaskControl 上调用 WaitFor(INFINITE),但它挂起。我进行了调试,可以看到 Invoke 调用上的方法已完成。当与 TOmniWorker 一起使用时,我是否误解了将 WaitFor 与 IOmniTaskControl 一起使用?
编辑:我编辑了测试文件夹中的 test_43_InvokeAnonymous 项目,我看到了相同的行为:
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);
挂起。
WaitFor
等待任务完成执行,但由于没有人告诉任务终止,它将永远等待。
安排后台操作然后等待它或多或少违背了后台执行的目的。最好安排一个后台任务,然后在任务完成时将通知发回主线程。使用 OnMessage
(in the main thread) and Task.Comm.Send
的任何变体(在 worker 中)。
更好的方法是使用 Parallel.Future
,它完全封装了您要执行的操作。
如果你真的需要等待 Invoke
完成,你可以在 Invoke
之前创建一个 waitable value,在 [=14= 执行的代码中通知它] 并在调用 Invoke
.