我对如何在动态创建的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;
我可以将唯一标识符传递给动态创建的线程,以便它可以在同步方法中显示它吗?
答案 0 :(得分:5)
这是一个经典的误解。我们理解匿名方法捕获,但它们捕获了什么?价值或变量?
答案是后者。他们捕获变量。有一个变量thrn
,您的六个匿名方法中的每一个都会捕获。由于存在一个变量,因此在任何一个时刻只有一个值。
当然,由于您在线程中执行代码,因此您对此变量进行了数据竞争。因此,我的“在任何一个时刻”附带条件。这就是为什么你有不可重复的,不可预测的结果。并且您可能在循环完成后访问循环变量,然后该值未定义。
如果希望每个匿名方法具有不同的值,则必须为每个匿名方法创建一个新变量。我对另一个问题的回答表明:Anonymous methods - variable capture versus value capture。
因此,为了说明您的上下文,我们需要更多的脚手架。
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;
答案 1 :(得分: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;
上面的代码捕获了对本地ID
变量的6个不同引用。每个都有不同的价值。
问题中的代码捕获单个变量引用。由于无法控制线程何时运行,因此无法预测它们将从变量引用中检索的值。您观察到的值6
是因为在循环完成后循环变量的值未定义。
要进一步了解匿名方法的工作原理并使用变量绑定,请阅读Variable Binding Mechanism。