I started to dig into Delphi (D11) PPL and wrote this small example:
procedure TForm2.LaunchTasks;
const
cmax = 5;
Var
ltask: ITask;
i,j: Integer;
begin
for i := 1 to cmax do
begin
j := i;
ltask := TTask.Create(
procedure ()
begin
Sleep(3000);
SendDebugFmt('Task #%d' ,[j])
end);
ltask.Start;
end;
end;
This is what debug window shows after running the procedure:
Task #5
Task #5
Task #5
Task #5
Task #5
how could it be? I most probably miss something obvious...
Embarcadero's documentation covers this in detail:
Anonymous Methods in Delphi: Variable Binding Mechanism
The documentation then goes into greater detail explaining exactly how the implementation captures variables, especially when multiple anonymous methods capture the same variable (as is the case in your example).
So, your issue has nothing to do with TTask/PPL itself, and everything to do with the fact that you are creating multiple anonymous procedures that share the
jvariable. They are capturing a reference to the variable itself, not its value. By the time all of the tasks have finished sleeping,jhas been set to its final value, which all of the tasks then output.The fix (which is also described in the same documentation above) is to have your loop pass the variable as a parameter to an intermediate function which then declares the anonymous method to capture the parameter. That way, each anonymous method is capturing a different variable, eg:
An alternative solution is to replace your loop with
TParallel.For()instead of usingTTaskdirectly, eg: