I have a laborious procedure that I would like to process in parallel using the new parallel Delphi XE7 library.
Here is the single-threaded version:
procedure TTerritoryList.SetUpdating(const Value: boolean); var i, n: Integer; begin if (fUpdating <> Value) or not Value then begin fUpdating := Value; for i := 0 to Count - 1 do begin Territory[i].Updating := Value; // <<<<<< Time consuming routine if assigned(fOnCreateShapesProgress) then fOnCreateShapesProgress(Self, 'Reconfiguring ' + Territory[i].Name, i / (Count - 1)); end; end; end;
In fact, nothing complicated happens. If the variable in the list of territories is changed or set to false, then the procedure will go around all sales territories and recreate the border of the territory (which is a laborious task).
So here is my attempt to make it parallel:
procedure TTerritoryList.SetUpdating(const Value: boolean); var i, n: Integer; begin if (fUpdating <> Value) or not Value then begin fUpdating := Value; n := Count; i := 0; TParallel.For(0, Count - 1, procedure(Index: integer) begin Territory[Index].Updating := fUpdating; // <<<<<< Time consuming routine TInterlocked.Increment(i); TThread.Queue(TThread.CurrentThread, procedure begin if assigned(fOnCreateShapesProgress) then fOnCreateShapesProgress(nil, 'Reconfiguring ', i / n); end); end ); end; end;
I replaced the for-loop with a parallel for-loop. Counter "i" is locked as it increases to indicate progress. I then end the OnCreateShapeProgress event in TThread.Queue, which will be handled by the main thread. The OnCreateShapeProgress event is handled by a routine that updates the progress bar and the label that describes the task.
The routine works if I exclude the OnCreateShapeProgress event call. It crashes with an EAurgumentOutOfRange error.
So my question is simple:
Am I doing anything stupid?
How do you call an event handler from a TParallel.For or TTask loop?