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

时间:2017-05-03 19:11:31

标签: multithreading delphi delphi-10.1-berlin

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 Berlin

编辑:

按照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;

2 个答案:

答案 0 :(得分:3)

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

如果您只定位Windows,请使用TMonitor。对于针对其他平台的代码,您应该使用"arn:aws:s3:::cf-templates-erb4urdcaiht-us-east-1"

答案 1 :(得分:0)

另一种选择是使用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;