1

我对如何将唯一标识符存储在动态创建的TThread.

我创建了这样的东西:

procedure TForm1.Button1Click(Sender: TObject);
var thrn:word;
begin
for thrn := 0 to 5 do//<--- this is a loop variable that should give the unique numbers
  TThread.CreateAnonymousThread(
    procedure()
    var
      i: longint;
      r: double;
      thrns:string;
    begin
      thrns:=inttostr(thrn);//in this thread? variable I try to store the ID as string
      repeat
        for i := 0 to 100000000 do
        begin
          r := random(high(i));//this loop gives some dummy job 
          r := sqr(r);         //to the thread to slow it down
        end;
        TThread.Synchronize(nil,
          procedure()
          begin
            memo1.Text:=memo1.Text+#13#10+
              'done'+thrns;//it returns strange IDs including '6'
          end);
      until false;
    end).Start;
end;

我可以将唯一标识符传递给动态创建的线程,以便它可以在其同步方法中显示它吗?

4

2 回答 2

5

这是一个经典的误解。我们知道匿名方法捕获,但它们捕获什么?值还是变量?

答案是后者。他们捕获变量。thrn您的六个匿名方法中的每一个都捕获了一个变量。因为只有一个变量,所以在任何一个时刻都只有一个值。

当然,由于您是在线程中执行代码,因此您在此变量上存在数据竞争。因此,我的“在任何时候”附带条件。这就是为什么你会得到不可重复、不可预测的结果。并且您可能会在循环完成后访问循环变量,然后该值未定义。

如果您希望每个匿名方法具有不同的值,则必须为每个匿名方法创建一个新变量。我对另一个问题的回答表明:匿名方法 - 变量捕获与值捕获

因此,为了在您的上下文中说明,我们需要更多的脚手架。

function GetThreadProc(thrn: Integer): TProc;
begin
  Result := 
    procedure
    begin
      // thrn is passed by value, so a copy is made, i.e. a new variable
      ....
    end;
end;

....

procedure TForm1.Button1Click(Sender: TObject);
var 
  thrn: Integer;
begin
  for thrn := 0 to 5 do
    TThread.CreateAnonymousThread(
      GetThreadProc(thrn)).Start;
end;
于 2015-12-12T16:11:13.140 回答
2

您必须捕获标识符的值。这是一个如何做到这一点的例子。

procedure TForm1.Button1Click(Sender: TObject);
  function GetAnonProc( ID: Word): TProc;
  begin
    Result :=
      procedure
      var
        i: longint;
        r: double;
        thrns:string;
      begin
        thrns:= inttostr(ID);// Capture value
        repeat
          for i := 0 to 100000000 do
          begin
            r := random(high(i));//this loop gives some dummy job
            r := sqr(r);         //to the thread to slow it down
          end;
          TThread.Synchronize(nil,
            procedure()
            begin
              memo1.Text:=memo1.Text+#13#10+
                'done'+thrns;//it returns strange IDs including '6'
            end);
        until false;
      end;

  end;
var
  thrn:word;
  p: TProc;
begin
  for thrn := 0 to 5 do
  begin
    p := GetAnonProc(thrn); // Capture thrn value
    TThread.CreateAnonymousThread(p).Start;
  end;
end;

上面的代码捕获了 6 个对局部ID变量的不同引用。每个都有不同的价值。

问题中的代码捕获单个变量引用。由于您无法控制线程何时运行,因此无法预测它们将从变量引用中检索到的值。您观察到的值6是因为循环变量的值在循环完成后未定义。

要进一步了解匿名方法的工作原理和使用变量绑定,请阅读变量绑定机制

于 2015-12-12T15:49:26.187 回答