考虑以下示例:
t1 := TTask.Run(
procedure
begin
sleep(Random(1000) + 100);
raise Exception.Create('Error Message 1');
end
);
t2 := TTask.Run(
procedure
begin
sleep(Random(1000) + 100);
raise Exception.Create('Error Message 2');
end
);
res := -1;
try
res:= TTask.WaitForAny([t1, t2]);
except
end;
write('Index: ' + intToStr(res)); // Prints "-1"
readln;
当其中一个任务失败时,WaitForAny会抛出异常,并且res变量未分配已完成任务的索引。相反,它包含" -1" (早先指定)。
在C#(TPL)Task.WaitAny
中也会抛出异常,但它会返回失败任务的索引。
有没有办法分配RES变量或获取失败任务的索引?
答案 0 :(得分:0)
您写道:
在C#(TPL)
Task.WaitAny
中也会抛出异常,但它会返回失败任务的索引。
那不是真的。考虑以下C#程序:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Task t1 = Task.Run(() => { throw new Exception("task 1"); });
Task t2 = Task.Run(() => { throw new Exception("task 2"); });
int index = Task.WaitAny(new Task[] { t1, t2 });
Console.WriteLine(index);
Console.ReadLine();
}
}
}
两个任务都抛出异常,但WaitAny
没有。它返回首先完成的任务的索引值,即使该任务引发了异常。
相比之下,如果要完成的第一个任务是通过引发异常,则Delphi TTask.WaitForAny
方法将引发异常。在这种情况下,由于函数引发异常时未分配函数返回值,因此您需要找到一种不同的方法来标识导致WaitForAny
返回的任务。例如,这是一种相当蹩脚的方法:
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.Threading;
type
ETaskException = class(Exception)
private
FTaskIndex: Integer;
public
constructor Create(const Msg: string; const TaskIndex: Integer);
property TaskIndex: Integer read FTaskIndex;
end;
constructor ETaskException.Create(const Msg: string; const TaskIndex: Integer);
begin
inherited Create(Msg);
FTaskIndex := TaskIndex;
end;
var
t1, t2: ITask;
i, res: Integer;
begin
t1 := TTask.Run(
procedure
begin
sleep(150);
raise ETaskException.Create('Task failed', 0);
end
);
t2 := TTask.Run(
procedure
begin
sleep(100);
raise ETaskException.Create('Task failed', 1);
end
);
try
res := TTask.WaitForAny([t1, t2]);
Writeln('Task succeeded, index ' + IntToStr(res));
except
on E:EAggregateException do begin
for i := 0 to E.Count-1 do begin
WriteLn('Task failed, index ' +
IntToStr((E.InnerExceptions[i] as ETaskException).TaskIndex));
end;
end;
end;
ReadLn;
end.
虽然我已经在这里讨论了聚合异常,但我相信WaitForAny
只会有一个内部异常。
您可能最好只循环查找Status
等于TTaskStatus.Exception
的任务。