Delphi:将异常捕获到TTask中并引发到主线程

时间:2019-07-04 13:52:33

标签: delphi

我想从主表单/主线程中捕获引发到TTask中的异常

var
    aTasks: array of ITask;
begin
    Setlength(aTasks, 2);

    aTasks[0] := TTask.Create(procedure begin
        raise Exception.Create('Error1');
    end);
    aTasks[0].Start;

    aTasks[1] := TTask.Create(procedure begin
        raise Exception.Create('Error2');
    end);
    aTasks[1].Start;

    TTask.WaitForAll(aTasks);
end;

进入主窗体(主线程),我看到以下内容:

enter image description here

我试图捕获异常并重新引发进入主线程

var
    aTasks: array of ITask;
begin
    Setlength(aTasks, 2);

    aTasks[0] := TTask.Create(procedure begin
        try
            raise Exception.Create('Error1');
        except on E : Exception do 
            begin
                TThread.Queue(TThread.CurrentThread, procedure
                begin
                    raise E;
                end);
            end;
        end;
    end);
    aTasks[0].Start;

    aTasks[1] := TTask.Create(procedure begin
        try
            raise Exception.Create('Error2');
        except on E : Exception do 
            begin
                TThread.Queue(TThread.CurrentThread, procedure
                begin
                    raise E;
                end);
            end;
        end;
    end);
    aTasks[1].Start;

    TTask.WaitForAll(aTasks);

end;

但进入主要形式后,我会看到以下内容:

enter image description here

如何捕获线程异常并将其重新引发到主线程?

更新

也许我已经找到了使用AcquireExceptionObject的正确方法:

var
    aTasks: array of ITask;
begin
  Setlength(aTasks, 2);

  aTasks[0] := TTask.Create(procedure
  var
      CapturedException : Exception;
  begin
      try
          raise Exception.Create('Error1');
      except
          CapturedException := AcquireExceptionObject;
          TThread.Queue(TThread.CurrentThread, procedure begin
              raise CapturedException;
          end);
      end;
  end);
  aTasks[0].Start;

  aTasks[1] := TTask.Create(procedure
  var
      CapturedException : Exception;
  begin
      try
          raise Exception.Create('Error2');
      except
          CapturedException := AcquireExceptionObject;
          TThread.Queue(TThread.CurrentThread, procedure begin
              raise CapturedException;
          end);
      end;
  end);
  aTasks[1].Start;

  TTask.WaitForAll(aTasks);
end;  

现在我看到了正确的错误:

enter image description here

这是将错误传播到主线程的标准方法吗?

1 个答案:

答案 0 :(得分:5)

TTask.WaitForAll()等待所有指定的任务完成。如果这些任务中的任何一个由于未捕获的异常而结束,则WaitForAll()会收集所有异常,并将EAggregateException引发到您的代码中:

procedure TForm4.Button1Click(Sender: TObject);
var ar : TArray<iTask>;
begin
  SetLength(ar, 3);
  ar[0] := TTask.Run(procedure begin
    TTask.CurrentTask.Wait(100);
    raise Exception.Create('Error Message');
  end);
  ar[1] := TTask.Run(procedure begin
    TTask.CurrentTask.Wait(100);
    raise Exception.Create('Another Error Message');
  end);
  ar[2] := TTask.Run(procedure begin
    TTask.CurrentTask.Wait(100);
    raise Exception.Create('A Third Error Message');
  end);

  try
    TTask.WaitForAll(ar);
  except
     on E: EAggregateException do ShowMessage(E.ToString);
  end;
//
//  [Dialog Content]
//  One or more errors occurred
//  Error Message
//  Another Error Message
//  A Third Error Message
//  [OK]
end;

EAggregateException具有公用的CountInnerExceptions[]属性,如果您想直接访问各个例外。