Larry Fuqua
Larry Fuqua

Reputation: 148

How can I check exceptions when using IOmniTaskControl/TOmniWorker?

I'm using an IOmniTaskControl/TOmniWorker to funnel code execution onto a specific thread. I'll reuse this IOmniTaskControl repeatedly for multiple Invoke calls. How do I check for exceptions that may have occurred during the Invoke? This is a follow on question to the question/answer: Waiting for Invoke to finish when using IOmniTaskControl/TOmniWorker.

I've checked the ExitCode and FatalException of the IOmniTaskControl but they are not set. It seems that the IOmniTaskControl will create a new task automatically for each Invoke call, and the exception gets placed onto that task, if it occurs. However, I have no reference to that task following the completion of the Invoke. I'm using a TOmniWaitableValue to flag when the invoke completes, but not clear on what I will need to do to make any exception that occurred available to me on return from the WaitFor(...).

Here is a snippet of the structure I have:

interface

type
  TMyTaskProc = reference to procedure;

  TMyTask = class
  private
    FWorker:      IOmniWorker;
    FTaskControl: IOmniTaskControl;
    FWaitable:    IOmniWaitableValue;
  public
    constructor Create;
    destructor Destroy; override;

    procedure AwaitInvoke(Proc: TMyTaskProc); overload;
  end;

implementation

type
  TMyTaskWorker = class(TOmniWorker);

constructor TMyTask.Create;
begin
  inherited;

  FWorker := TMyTaskWorker.Create;
  FTaskControl := CreateTask(FWorker).Run;
  FWaitable := TOmniWaitableValue.Create;
end;

destructor TMyTask.Destroy;
begin
  FTaskControl.Terminate;
  FTaskControl := nil;

  FWaitable := nil;

  inherited;
end;

procedure TMyTask.AwaitInvoke(Proc: TMyTaskProc);
begin
  FWaitable.Reset;

  FTaskControl.Invoke(
    procedure
    begin
      try
        Proc();
      finally
        FWaitable.Signal;
      end;
    end
  );

  FWaitable.WaitFor(INFINITE);
end;

So in the above setup, how can I check after FWaitable.WaitFor(INFINITE) for any exception that might have occurred during the Proc() call. I'd like to just raise it again at that point in the calling thread.

Upvotes: 1

Views: 196

Answers (1)

gabr
gabr

Reputation: 26830

You have to catch the exception at the point when you call Proc and then somehow notify the caller of the situation. For example:

FTaskControl.Invoke(
  procedure
  var
    return: TOmniValue;
  begin
    return := TOmniValue.Null;
    try
      try
        Proc();
      except
        return.AsException := AcquireExceptionObject;
      end;
    finally
      FWaitable.Signal(return);
    end;
  end
);

FWaitable.WaitFor(INFINITE);
if FWaitable.Value.IsException then begin
  Writeln('Caught exception ' + FWaitable.Value.AsException.ClassName);
  FWaitable.Value.AsException.Free;
end;

Upvotes: 2

Related Questions