鉴于以下情况,匿名线程读取的DoSomething中AValue的值是否保证“可读”?即,我期待的价值?对我来说,我认为并不是因为DoSomething在线程实际执行之前超出了范围(即返回)(通过认识到x:= 2行总是在我的线程开始之前执行而很容易看出 - 虽然我想用线程所有投注都关闭,我的线程可能在DoSomething返回之前执行。)
我只是问,因为我在测试中从未遇到过AValue不等于1的情况(也就是传入的值)所以我想知道是否对程序和/或线程持有一些隐式引用(再次不太可能,因为CreateAnonymousMethod只是创建一个TThread后代的实例(TAnonymousThread)并调用我的匿名“执行”方法)。我猜测它是相同的,因为没有(在这种有限的情况下)覆盖了AValue存储位置的内存位置。
procedure TForm2.Button1Click(Sender: TObject);
var
x: Integer;
begin
x := 1;
DoSomething(x);
x := 2;// this line is only here for the purposes of placing a break point
end;
procedure TForm2.DoSomething(AValue: Integer);
begin
TThread.CreateAnonymousThread(
procedure
var
y: Integer;
begin
y := AValue;
if y = 1 then
MessageBox(0, 'Same', 'Value', MB_ICONINFORMATION or MB_OK)
else
MessageBox(0, 'Different', 'Value', MB_ICONINFORMATION or MB_OK)
end).Start;
end;
修改 只是为了验证,我想知道在匿名线程的上下文中捕获局部变量是否安全。
答案 0 :(得分:2)
您正在按值传递x。这意味着当您调用DoSomething()
时会复制x的值。
因此,每当执行匿名线程时,它都没有引用x。
该线程使用了捕获的变量,该变量使用原始值x
进行初始化。
换句话说,匿名线程无法看到您是否在ButtonClick1
事件中更改了x。
注意,如果在构造匿名线程后更改AValue
中的本地DoSomething()
,则会影响线程的结果。
procedure TForm2.DoSomething(AValue: Integer);
begin
TThread.CreateAnonymousThread(
procedure
var
y: Integer;
begin
y := AValue;
if y = 1 then
MessageBox(0, 'Same', 'Value', MB_ICONINFORMATION or MB_OK)
else
MessageBox(0, 'Different', 'Value', MB_ICONINFORMATION or MB_OK)
end).Start;
AValue := 3; // <-- This value will likely be seen by the anonymous thread.
end;
如果您想避免这种情况,您可以捕获AValue
这样的值:
procedure TForm4.DoSomething(AValue: Integer);
function CaptureValue( y: Integer) : TProc;
begin
Result :=
procedure
begin
if y = 1 then
MessageBox(0, 'Same', 'Value', MB_ICONINFORMATION or MB_OK)
else
MessageBox(0, 'Different', 'Value', MB_ICONINFORMATION or MB_OK)
end;
end;
var
p : TProc;
begin
p := CaptureValue(AValue);
TThread.CreateAnonymousThread( p)
.Start;
AValue := 3; // <-- The anonymous method is unaffected by this change !
end;
documentation解释了外部局部变量AValue是通过匿名方法引用捕获的:
如果匿名方法引用其正文中的外部局部变量,则该变量将被捕获&#34;。捕获意味着延长变量的生命周期,使其与匿名方法值一样长,而不是死于其声明例程。请注意,变量捕获捕获变量 - 而不是值。如果变量的值在通过构造匿名方法捕获后发生更改,则捕获的匿名方法的变量值也会更改,因为它们是具有相同存储的相同变量。捕获的变量存储在堆上,而不是堆栈中。