gpt4 book ai didi

delphi - IOmniParallelTask​​ 的异常处理不起作用

转载 作者:行者123 更新时间:2023-12-03 15:54:07 25 4
gpt4 key购买 nike

IOmniParallelTask​​ 执行中未处理的异常应该(据我理解文档)由 OTL 捕获并附加到 IOmniTaskControl 实例,该实例可以由 访问来自 IOmniTaskConfig 的 >终止处理程序

因此,在使用终止处理程序设置IOmniParallelTask​​实例后,如下所示:

fTask := Parallel.ParallelTask.NoWait.NumTasks(1);
fTask.OnStop(HandleOnTaskStop);

fTask.TaskConfig(Parallel.TaskConfig.OnTerminated(HandleOnTaskThreadTerminated));
fTask.Execute(TaskToExecute);

TaskToExecute 中任何未处理的异常:

procedure TFormMain.TaskToExecute;
begin
Winapi.Windows.Sleep(2000);
raise Exception.Create('async operation exeption');
end;

应附加到您在终止处理程序中获得的IOmniTaskControl实例:

procedure TFormMain.HandleOnTaskThreadTerminated(const task: IOmniTaskControl);
begin
if not Assigned(task.FatalException) then
Exit;

memo.Lines.Add('an exception occured: ' + task.FatalException.Message);
end;

此时的问题是,异常未分配IOmniTaskControl.FatalException,我不知道为什么。

也许你们中的一些人对我做错了什么有一些想法。整个 VCL 示例项目可以在这里找到:https://github.com/stackoverflow-samples/OTLTaskException

最佳答案

这是一个抽象层问题。 Parallel.ParallelTask​​ 将线程代码异常存储在本地字段中,该字段与 IOmniTaskControl.FatalException 属性不同步。 (我确实同意这不是一个好的行为,但我还不确定解决这个问题的最佳方法是什么。)

当前访问 IOmniParallelTask​​ 对象捕获的异常的唯一方法是调用其 WaitFor 方法。 IOmniParallelTask​​ 实际上应该公开一个 FatalException/DetachException 对,就像 IOmniParallelJoin 一样。 (再次,一个疏忽,应该在未来修复。)

解决当前 OTL 问题的最佳方法是在终止处理程序中调用 WaitFor 并捕获异常。

procedure TFormMain.HandleOnTaskThreadTerminated(const task: IOmniTaskControl);
begin
try
fTask.WaitFor(0);
except
on E: Exception do
memo.Lines.Add('an exception occured: ' + E.Message);
end;
CleanupTask;
end;

我还删除了 HandleOnTaskStop 并将清理工作移至终止处理程序。否则,在调用 HandleOnTaskThreadTermulated 时,fTask 已经为 nil

<小时/>

编辑

DetachExceptionFatalExceptionIsExceptional 已添加到 IOmniParallelTask​​ 中,因此现在您可以简单地执行以下操作您首先想要的(除了您必须使用 fTask,而不是 task)。

procedure TFormMain.HandleOnTaskThreadTerminated(const task: IOmniTaskControl);
begin
if not assigned(fTask.FatalException) then
Exit;

memo.Lines.Add('an exception occured: ' + FTask.FatalException.Message);
CleanupTask;
end;
<小时/>

编辑2

如注释中所述,OnTerminate 处理程序与一项任务相关。在此示例中,这不是问题,因为代码确保只有一个后台任务正在运行 (NumTasks(1))。

但是,在一般情况下,应使用 OnStop 处理程序来实现此目的。

procedure TFormMain.btnExecuteTaskClick(Sender: TObject);
begin
if Assigned(fTask) then
Exit;

memo.Lines.Add('task has been started..');
fTask := Parallel.ParallelTask.NoWait.NumTasks(1);
fTask.OnStop(HandleOnStop);
fTask.Execute(TaskToExecute);
end;

procedure TFormMain.HandleOnStop;
begin
if not assigned(fTask.FatalException) then
Exit;

memo.Lines.Add('an exception occured: ' + FTask.DetachException.Message);
TThread.Queue(nil, CleanupTask);
end;

由于 HandleOnStop 在后台线程中调用(因为使用了 NoWait),所以 CleanupTask 必须调度回主线程,如下所示在原始代码中。

关于delphi - IOmniParallelTask​​ 的异常处理不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34246361/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com