简体   繁体   English

为什么循环变量的值不存储在动态创建的AnonymousThread中

[英]Why the value of the loop variable is not stored in a dynamically created AnonymousThread

I have some academic interest of how I can store a unique identifier in a dynamically created TThread . 我对如何在动态创建的TThread存储唯一标识符有一些学术兴趣。

I create something like this: 我创建这样的东西:

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;

Can I pass a unique identifier to the dynamically created thread so that it could show it in its synchronize method? 我可以将唯一标识符传递给动态创建的线程,以便它可以在其sync方法中显示它吗?

This is a classic misunderstanding. 这是一个经典的误解。 We understand that anonymous methods capture, but what do they capture? 我们知道匿名方法会捕获,但是它们捕获了什么? The value or the variable? 值还是变量?

The answer is the latter. 答案是后者。 They capture the variable. 他们捕获变量。 There is a single variable, thrn , that each of your six anonymous methods capture. 六个匿名方法中的每一个都捕获一个变量thrn Since there is one variable, there is only one value, at any one moment in time. 由于只有一个变量,所以在任何时刻都只有一个值。

Of course, since you are executing code in threads, you have a data race on this variable. 当然,由于您是在线程中执行代码,因此在此变量上存在数据争用。 Hence my "at any one moment in time" proviso. 因此,我的“任何时候”附带条件。 And that's why you have unrepeatable, unpredictable results. 这就是为什么您无法获得不可预测的结果的原因。 And you are likely to access the loop variable after the loop has completed and the value then is undefined. 并且您很可能在循环完成之后访问循环变量,然后该值未定义。

If you wish to have a different value for each anonymous method, you must make a new variable for each anonymous method. 如果希望每个匿名方法都具有不同的值,则必须为每个匿名方法创建一个新变量。 My answer to another question demonstrates that: Anonymous methods - variable capture versus value capture . 我对另一个问题的回答表明: 匿名方法-变量捕获与值捕获

So, to illustrate in your context we need some more scaffolding. 因此,为了说明您的情况,我们需要更多的脚手架。

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;

You have to capture the value of your identifier. 您必须捕获标识符的值。 Here is an example how to do that. 这是一个示例。

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;

The code above captures 6 different references to a local ID variable. 上面的代码捕获了对本地ID变量的6种不同引用。 Each with a different value. 每个都有不同的值。

The code in the question captures a single variable reference. 问题中的代码捕获单个变量引用。 Since you cannot control when the threads are running, there is no way to predict what value they will retrieve from the variable reference. 由于您无法控制线程何时运行,因此无法预测它们将从变量引用中检索什么值。 The value 6 you observe is because of the fact that a loop variable's value is undefined after the loop is completed. 您观察到的值6是由于以下事实:循环完成后,循环变量的值未定义。

To further understand how anonymous methods works and use variable binding, read Variable Binding Mechanism . 要进一步了解匿名方法如何工作并使用变量绑定,请阅读变量绑定机制

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 来自AnonymousThread的结果-怎么样? - result from AnonymousThread - how? 为什么价值变量没有改变? - why value variable is not changed? mysql 存储过程,select 最大值并插入值并分配给变量 - mysql stored procedure, select max value and insert the value and assign to variable 当多个线程为其设置相同的值时,正确的值可以存储在变量中吗? - Can right value is stored in variable when multitple thread set same value to it? 为什么在 While 循环后 boolean 变量仍然为真? - Why boolean variable after While loop still true? 变量在线程中更新,但更新后的值不反映在循环内 - Variable is updated in a thread but updated value does not reflect inside a loop 无法获取存储在Java线程本地对象中的变量的整数值 - Unable to get Integer Value of Variable Stored in Java Thread Local Object 为什么可以在同一个类中创建的另一个线程中访问局部变量? - Why can a local variable be accessed in another thread created in the same class? 在循环创建的子线程中访问主线程变量时出现意外结果 - Unexpected result when accessing main thread variable in loop created child threads 为什么变量绑定会影响循环体内的生命周期? - Why does variable binding affect lifetime inside a loop body?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM