1

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.

Community
  • 1
  • 1
Larry Fuqua
  • 148
  • 1
  • 5
  • Couldn't you produce a complete program that raised an exception? That way we wouldn't need to guess. It feels like we have to ask this on almost every question here. – David Heffernan Mar 28 '16 at 16:06
  • Not sure if it was clear or not, but I wasn't talking about a specific exception. I'm just trying to setup the code to handle possible exceptions in the Proc() call. Didn't seem necessary to provide a full working program that include a bogus exception in the Proc() call. In fact, Gabr has given me the answer I needed. – Larry Fuqua Mar 28 '16 at 17:30
  • Well carry on writing half a question then. If you got what you needed, what else matters? – David Heffernan Mar 28 '16 at 17:32

1 Answers1

2

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;
gabr
  • 26,580
  • 9
  • 75
  • 141
  • 2
    That's no good. The exception object gets destroyed when the exception handler completes. You need `AcquireExceptObject`. – David Heffernan Mar 28 '16 at 17:21
  • 1
    @DavidHeffernan, of course. I forgot how my own software works :( (Was under the impression that TOmniValue.AsException handles that.) Fixed. – gabr Mar 28 '16 at 17:31
  • Thanks catching the exception myself and funneling was the approach that I was going to take if there wasn't something I was missing to already provide the capability I need. And I would use AqcuireExceptObject. – Larry Fuqua Mar 28 '16 at 17:32
  • Does feel like it would be good to have some built in support for 'await' on the invoke that could take care of these things. But I think I'm good to go for now. – Larry Fuqua Mar 28 '16 at 17:33