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.
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;