将线程对象传递给另一个类后,线程变量丢失/改变了吗?

时间:2017-01-12 12:19:06

标签: multithreading delphi

我写了一个显示我问题的小程序:

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"。

为什么物体会丢失?

1 个答案:

答案 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

尽管如此,这并不会给你带来可预测的结果。线程过程独立于主线程执行。当您从主线程读取变量时,线程可能会或可能不会修改变量。这被称为数据竞赛。如果您希望等到变量被修改之后,那么您可以使用例如一个事件对象来允许线程发出信号表明该变量已准备好被读取。