我写了一个显示我问题的小程序:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
TThread_A = class(TThread)
private
stupidvariable : integer;
protected
procedure Execute; override;
public
property getstupidvar : integer read stupidvariable;
constructor Create;
end;
TSomeClass = class
private
m_Obj : ^TThread_A;
procedure readVar;
public
constructor Create(obj: TThread_A);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TSomeClass.Create(obj: TThread_A);
begin
m_Obj := @obj;
readVar;
end;
procedure TSomeClass.readVar;
begin
showmessage(inttostr(m_Obj.getstupidvar));
end;
constructor TThread_A.Create;
begin
inherited Create(false);
FreeOnTerminate := True;
end;
procedure TThread_A.Execute;
begin
stupidvariable := 100;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
threadA : TThread_A;
someClass : TSomeClass;
begin
threadA := TThread_A.Create;
someClass := TSomeClass.Create(threadA);
end;
end.
这里到底发生了什么? 我以为我正在传递对象" threadA" to someClass并指定" threadA"的地址到" m_Obj"。
为什么物体会丢失?
答案 0 :(得分:2)
static
这里constructor TSomeClass.Create(obj: TThread_A);
begin
m_Obj := @obj;
readVar;
end;
(本质上)是一个局部变量,因此它的生命周期在函数返回时结束。因此,您已经记住了不再存在的东西的地址。
obj
是一个类,而类是引用类型,所以它已经是一个指针。变化
TThread_A
到
m_Obj: ^TThread_A;
和
m_Obj: TThread_A;
到
m_Obj := @obj;
现在你正在获取对实例的引用的副本,这是我认为你的意思。
但即使这样,你也会得到一个有效的程序。因为您设置了m_Obj := obj;
,所以线程可以随时销毁。这意味着您不能保留对它的引用,因为该引用可能在您的背后变得无效。因此,您还应将FreeOnTerminate
设置为FreeOnTerminate
。
尽管如此,这并不会给你带来可预测的结果。线程过程独立于主线程执行。当您从主线程读取变量时,线程可能会或可能不会修改变量。这被称为数据竞赛。如果您希望等到变量被修改之后,那么您可以使用例如一个事件对象来允许线程发出信号表明该变量已准备好被读取。