正确构造ParallelTask​​(IOmniParallelTask​​),取消&终止处理程序

时间:2015-12-01 15:34:30

标签: delphi delphi-xe6 omnithreadlibrary

我在阅读文档后正在玩OmniThreadLibrary,但我仍然面临构建ParallelTask​​的一些简单/早期问题。

cancellationTokenterminationHandler构建ParallelTask​​之后,异步执行完成后我没有执行terminationHandler.OnTerminatedOnStop,我无法找到出于何种原因: - (

我希望一些OTL专业人士可以帮助我解决这个问题。

我想要实现的目标

  • 执行异步操作
  • 取消时取消执行(canceltoken)
  • 在异步操作完成时在mainthread中执行一些代码(检查异常)

到目前为止我做了什么

阅读文档后,我创建了一个ParallelTask​​,通过cancellationToken设置terminationHandlerTaskConfig并执行操作。 执行的操作本身会检查发出信号的cancellationToken并执行其工作(此处为1s的Sleep)。 HandleOnTerminated方法检查 错误并设置fIsDone和fHasError标志,由来自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.

有了代码的和平,fIsDone永远不会被设置,因为永远不会调用HandleOnTerminateHandleOnStop。所以从上面的例子 以下ConsoleApplication似乎永远不会结束:

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.

1 个答案:

答案 0 :(得分:2)

正如评论中所述,我遇到的问题是由consoleapplication本身引起的,因为它不包含messageloop(在我的例子中是一个DUnitX项目)。

由于OTL通信似乎基于windowsmessages,因此在没有工作消息循环的情况下不会触发OnTerminated和OnStop。