3

ドキュメントを読んだ後、OmniThreadLibrary をいじっているだけですが、ParallelTask​​ の構築に関する簡単な/初期の問題にまだ直面しています。

cancellationTokenterminationHandlerを使用した ParallelTask​​ の構築後、非同期実行が完了した後に実行さterminationHandler.OnTerminatedOnStopず、理由を見つけることができませんでした:-(

OTL の専門家の何人かが、これについて私を助けてくれることを願っています。

私が達成したいこと:

  • 非同期操作を実行する
  • キャンセル時に実行を停止 (cancellationtoken)
  • 非同期操作が完了すると、メインスレッドでコードを実行します (例外をチェックします)。

私がこれまでにやったこと

ドキュメントを読んだ後、ParallelTask​​ を作成し、セットアップしcancellationTokenて操作terminationHandlerTaskConfig実行しました。実行された操作自体は、cancellationTokenシグナルが送信されていることを確認し、その作業を行います (ここでは 1 のスリープ)。このHandleOnTerminatedメソッドはエラーをチェックし、fIsDone フラグと fHasError フラグを設定して、メインスレッドから読み取ります。

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は、 が設定されることはHandleOnTerminateありHandleOnStopません。したがって、上記の例では、次の 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.
4

1 に答える 1

2

コメントに投稿されているように、私が直面していた問題はコンソールアプリケーション自体が原因でした。これは、メッセージループ (私の場合は DUnitX プロジェクト) が含まれていないためです。

OTL 通信は Windows メッセージに基づいているように見えるため、メッセージループが機能していない場合、OnTerminated と OnStop はトリガーされません。

于 2015-12-01T19:52:35.430 に答える