Search code examples
delphiforeachparallel-processingomnithreadlibrary

How to terminate a parallel.foreach from OTL in Delphi xe2


I am learning how to use OmniThreadLibrary in Delphi XE2, i wonder if someone can show me how to cancel a parallel.foreach.

I read that I should use a cancellation token, but I cannot find an example of some sort on how to use it.

This is the original for loop inside the function.

function SomeFunction() : string;
begin

  for value :=  0 to length(listOfThings)-1 do
  begin

    Chain := Function1( listOfThings[value] );

    if Evaluate( Chain , Solution) then
      Parameters[value] := Solution
    else
    begin
      Result := 'ERROR';
      exit;
    end;
  end;
end;

And this is how I am using the Parallel.ForEach

function SomeFunction() : string;
begin

  Parallel.ForEach(0, length(listOfThings)-1 ).Execute(

    procedure (const value: integer)
        var Chain : string;
        begin
          Chain := Function1(listOfThings[value]);

        if Evaluate(Chain , Solution) then
          Parameters[value] := Solution
        else
          begin
            Result := 'ERROR';    //Here is where it won't work
            exit;  
          end;
        end
  );
end;

Inside the Parallel.ForEach I can't do Result := 'ERROR' because it is not captured inside the procedure, so I think if I can cancel the Parallel.ForEach and report that cancellation, then I can just assign Result := 'ERROR' outside.

But I am new to OmniThreadLibrary and I don't know how to do such a thing, please help me :)


Solution

  • You need to use a cancellation token:

    var
      cancelToken: IOmniCancellationToken;
    

    You obtain the cancellation token by calling CreateOmniCancellationToken from the OtlSync unit.

    cancelToken := CreateOmniCancellationToken;
    

    You then supply the token to the parallel loop:

    Parallel.ForEach(...)
        .CancelWith(cancelToken)
        .Execute(...);
    

    And you signal the cancellation token by calling its Signal method.

    cancelToken.Signal;
    

    From outside the parallel loop you can use

    cancelToken.IsSignaled
    

    to detect that you cancelled. Or you can capture a boolean variable from the surrounding scope and pass the information through that variable.

    The example here gives an illustration.