[英]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.