Reputation: 532
I am just playing around with the OmniThreadLibrary after reading the docs, but I am still facing some simple/early problems on constructing a ParallelTask.
After the construction of a ParallelTask with cancellationToken
and terminationHandler
, terminationHandler.OnTerminated
and OnStop
are not being executed after the async execution is done and I was not able to find out why :-(
I hope some of the OTL pros can help me out on this one.
What I want to achieve:
What I did so far:
After reading the docs I created a ParallelTask, setting up cancellationToken
and terminationHandler
via TaskConfig
and executed the operation.
The executed operation itself checks for the cancellationToken
being signalled and does its work (here a Sleep of 1s). The HandleOnTerminated
method checks for
errors and sets the fIsDone and fHasError flags, getting read by someone from mainthread.
unit OTLSetup.Async;
interface
uses
OtlParallel, OtlSync, OtlTaskControl, OtlTask;
type
IAsyncOperation = interface
['{6B10AB46-DEB6-48F5-AC36-E9327AA54C82}']
procedure Execute;
procedure Cancel;
function IsDone: boolean;
end;
TAsyncOperation = class(TInterfacedObject, IAsyncOperation)
protected
fParallelTask: IOmniParallelTask;
fCancellationToken: IOmniCancellationToken;
fIsDone: boolean;
procedure HandleOnTerminated(const task: IOmniTaskControl);
procedure HandleOnStop;
procedure AsyncOperation(const task: IOmniTask);
public
procedure Execute;
procedure Cancel;
function IsDone: boolean;
end;
implementation
uses
Winapi.Windows;
{ TAsyncOperation }
procedure TAsyncOperation.Cancel;
begin
fCancellationToken.Signal;
end;
procedure TAsyncOperation.Execute;
begin
if Assigned(fParallelTask) then
Exit;
fIsDone := false;
fCancellationToken := CreateOmniCancellationToken;
fParallelTask := Parallel.ParallelTask;
fParallelTask.NoWait.NumTasks(1);
fParallelTask.TaskConfig(Parallel.TaskConfig.CancelWith(fCancellationToken).OnTerminated(HandleOnTerminated));
fParallelTask.OnStop(HandleOnStop);
fParallelTask.Execute(AsyncOperation);
end;
procedure TAsyncOperation.AsyncOperation(const task: IOmniTask);
var
I: Integer;
begin
for I := 0 to 5 do
if task.CancellationToken.IsSignalled then
Exit
else
Winapi.Windows.Sleep(1000);
end;
procedure TAsyncOperation.HandleOnStop;
begin
fParallelTask := nil;
fIsDone := true;
end;
procedure TAsyncOperation.HandleOnTerminated(const task: IOmniTaskControl);
begin
fParallelTask := NIL;
fIsDone := true;
end;
function TAsyncOperation.IsDone: boolean;
begin
result := fIsDone;
end;
end.
With this peace of Code, fIsDone
is never set, because HandleOnTerminate
and HandleOnStop
are never called. So with the exmaple from above
the following ConsoleApplication seems to never end:
program OTLSetup;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
OTLSetup.Async in 'OTLSetup.Async.pas';
var
LAsync: IAsyncOperation;
begin
LAsync := TAsyncOperation.Create;
try
LAsync.Execute;
while not LAsync.IsDone do
Writeln('Async task still running');
Writeln('Async task finished');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Upvotes: 3
Views: 287
Reputation: 532
As posted in the comments, the issue I was facing has been caused by the consoleapplication itself, because it does not contain a messageloop (in my case a DUnitX project).
Because the OTL communication seems to be based on windowsmessages, OnTerminated and OnStop are not triggered in absence of a working messageloop.
Upvotes: 2