如何从 TParallel.For 循环线程写入访问字符串变量?

How to write-access a string variable from a TParallel.For loop thread?

System.Threading.TParallel.For 循环中,我需要写访问在 TParallel.For 循环线程之外声明的字符串变量:

// Main thread:
procedure TForm2.GetWeather;
var
  CurrentWeather: string;
begin
  CurrentWeather := 'Current weather: ';

  System.Threading.TParallel.For(1, 10,
    procedure(idx: Integer)
    begin
      if IsRainy(idx) then
      begin
        // loop thread needs to write-access a mainthread-string-variable:
        CurrentWeather := CurrentWeather + 'bad weather, ';
      end;
    end);

  Self.Caption := CurrentWeather;
end;

但是根据文档,不应该这样做。而且 System.SyncObjs.TInterlocked 似乎没有写入字符串变量的方法。

那么在这种情况下我如何写入 CurrentWeather 变量?

Delphi 10.1.2 柏林

编辑:

根据 David Heffernan 的建议,我重写了代码 - 这是否正确?:

// Main thread:
procedure TForm2.GetWeather;
var
  CurrentWeather: string;
  ALock: TCriticalSection;
begin
  CurrentWeather := 'Current weather: ';

  ALock := TCriticalSection.Create;
  try
    System.Threading.TParallel.For(1, 10,
      procedure(idx: Integer)
      begin
        if IsRainy(idx) then
        begin
          ALock.Enter;
          try
            CurrentWeather := CurrentWeather + 'bad weather, ';
          finally
            ALock.Leave;
          end;
        end;
      end);
  finally
    ALock.Free;
  end;

  Self.Caption := CurrentWeather;
end;

您需要使用锁来修改像string这样的复杂数据类型。这不能以原子方式完成。

如果您只定位 Windows,请使用 TCriticalSection。对于针对其他平台的代码,您应该使用 TMonitor.

另一种选择是使用 TThread.Queue,例如像这样(假设您想要动态更新标题,而不是累积结果并在所有线程完成后显示它)

procedure TForm1.Button6Click(Sender: TObject);
begin
  Caption := 'Current weather: ';
  TParallel.For(1, 10,
    procedure(idx: Integer)
    begin
      if IsRainy(idx) then
      begin
        // loop thread needs to write-access a mainthread-string-variable:
        TThread.Queue(TThread.Current,
        procedure
        begin
          Caption := Caption + 'bad weather, ';
        end)
      end;
    end);
end;