Question

Using the OmniThreadLibrary and Delphi XE4, I am hoping to run multiple threads that process data in the background, adding speed increases to my already existing code.

When calling the procedure below, the Application GUI stops processing any input until all of the threads have completed. My understanding is that using .NoWait should allow the procedure to exit even when the threads are running.

procedure Test(input: TStringList; output: TList<TMaintFore>);
var
  outQueue: IOmniBlockingCollection;
  transaction: TOmniValue;
begin
  outQueue := TOmniBlockingCollection.Create;
  Parallel.ForEach(0, input.Count - 1)
    .NoWait
    .Into(outQueue)
    .Execute(
      procedure(const value: integer; var result: TOmniValue)
      begin
        result := TMaintFore.Create(input[value]);
      end
    );
end;

Is my understanding of the ForEach loop incorrect, suggesting I should use an alternate method to achieve background processing? Any suggestions on the correct use of the OmniThreadLibrary is appreciated.

Was it helpful?

Solution

You have to store the interface returned from the Parallel.ForEach in a global (form etc) variable and destroy it only when the ForEach finishes execution.

In your example, the result of ForEach is stored in a temporary variable which is destroyed when the Test procedure exits. The ForEach destructor waits for all tasks to complete and that blocks your program.

The safest (but admittedly non-obvious) way to destroy the foreach interface on task completion is to use the OnStop method and from it queue a command to the main thread.

var
  loop: IOmniParallelLoop<integer>;

loop := Parallel.ForEach(1, N).NoWait;
loop.OnStop(
  procedure (const task: IOmniTask)
  begin
    task.Invoke(
      procedure
      begin
        // do anything
        loop := nil;
      end);
  end);
loop.Execute(
  procedure (const value: integer)
  begin
    ...
  end);

This is documented in the wiki.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top