将字符串变量传递给线程不安全?

问题描述 投票:0回答:1

如果我运行此代码,结果会出乎意料,因为线程中的字符串没有正确的值:

procedure TMain.FollowBose(Speakername: string; NewState: Boolean);
{..}
procedure TMain.ProcessRoomMotionResponse(Rooms: TJSONArray; Response: TJSONObject);
var
  ParamName1: string;
  ParamName2: string;
  Room: tJSONValue;
  RoomData: TJSONObject;
  Roomname: string;
  Motion: Boolean;
begin
  if Assigned(Rooms) then begin
    ParamName1 := 'Room';
    ParamName2 := 'Motion';
    for Room in Rooms do begin
      RoomData := Room as TJSONObject;
      if Assigned(RoomData.Values[ParamName1]) and Assigned(RoomData.Values[ParamName2]) then begin
        Roomname := RoomData.Values[ParamName1].Value;
        Motion := RoomData.Values[ParamName2].AsType<Boolean>;
        LogWrite('Launching sub for ' + Roomname + '-FollowUp.', Debug);
        TThread.CreateAnonymousThread(
          procedure
          begin
            FollowUp(Roomname, Motion);
          end).Start;
      end;
    end;
  end;
end;

由于字符串很特殊,这是可以预料的吗?

multithreading delphi
1个回答
0
投票

这与具体的字符串无关,而是与匿名过程如何捕获变量有关。这是有记录的行为:

Delphi 中的匿名方法

请参阅“匿名方法变量绑定”部分。

您与所有线程共享相同的

Roomname
Motion
局部变量,而不是为每个线程提供自己的变量副本。因此,当循环运行时,所有线程都会看到分配给变量的最后一个值。

试试这个:

procedure TMain.ProcessRoomMotionResponse(Rooms: TJSONArray; Response: TJSONObject);
var
  ParamName1: string;
  ParamName2: string;
  Room: tJSONValue;
  RoomData: TJSONObject;
  Roomname: string;
  Motion: Boolean;

  procedure DoFollowUp(ARoomName: string; AMotion: Boolean);
  begin
    LogWrite('Launching sub for ' + ARoomName + '-FollowUp.', Debug);
    TThread.CreateAnonymousThread(
      procedure
      begin
        FollowUp(ARoomname, AMotion);
      end).Start;
  end;

begin
  if Assigned(Rooms) then begin
    ParamName1 := 'Room';
    ParamName2 := 'Motion';
    for Room in Rooms do begin
      RoomData := Room as TJSONObject;
      if Assigned(RoomData.Values[ParamName1]) and Assigned(RoomData.Values[ParamName2]) then begin
        Roomname := RoomData.Values[ParamName1].Value;
        Motion := RoomData.Values[ParamName2].AsType<Boolean>;
        DoFollowUp(Roomname, Motion);
      end;
    end;
  end;
end;
© www.soinside.com 2019 - 2024. All rights reserved.