0

Giving the following code:

procedure TForm1.Button1Click(Sender: TObject);
var
  myTask: ITask;
begin

  myTask := TTask.Run(
    procedure
    var
      i: Integer;
    begin
      for i := 0 to 3 do
      begin
        TThread.ForceQueue(
            nil
          , procedure
            begin
              ShowMessage('Count: ' + i.ToString);
            end
        );

        //I know this will work
//        TThread.Synchronize(
//            nil
//          , procedure
//            begin
//              ShowMessage('Count: ' + i.ToString);
//            end
//        );

      end;
    end
  );
end;

This will always print "Count: 4"

Is there a way to keep the variable i when the queued anonymous procedure is executed?

I know it will work using Synchronize(), but I prefer using Queue because in my real case the queued method writes some log in a file. My task doen't need to wait for the log, that's why I prefer using Queue().

I'm using Delphi 10.3.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
phepher
  • 3
  • 1
  • 2
  • 3

1 Answers1

1

First, you should be using TThread.Queue() rather than TThread.ForceQueue(). The latter is meant to be used only in the main UI thread, not in a task thread.

Second, an anonymous method captures variable references, not values. Read the documentation, especially the section titled "Variable Binding Mechanism". You are queuing up 4 anonymous methods that are sharing a single variable, that is why all of their results are the same value.

To solve this, move the capture inside another procedure so the anonymous methods are not sharing a single variable anymore. For example:

procedure TForm1.Button1Click(Sender: TObject);
var
  myTask: ITask;
begin
  myTask := TTask.Run(
    procedure
    var
      i: Integer;
      procedure DoQueue(Value: Integer);
      begin
        TThread.Queue(
            nil
          , procedure
            begin
              ShowMessage('Count: ' + Value.ToString);
            end
        );
      end;
    begin
      for i := 0 to 3 do
      begin
        DoQueue(i);
      end;
    end
  );
end; 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770