Delphi - TThread可以在主VCL线程中更改变量的值吗?

Ste*_*e F 1 delphi tthread

使用:Delphi XE2,Windows VCL Forms应用程序

TThread在执行期间是否可以更改主VCL线程中变量的值?

需要更新一个被声明为TForm类的字段的Integer.它将作为重载(并重新引入)Create构造函数方法中的var变量传递给TThread.

这有什么后盾吗?

Rob*_*edy 10

是的,线程可以修改变量.变量不属于线程.变量可以属于表单或线程对象,但是线程对象(即,TThread其后代的实例或其后代)与OS执行线程不同.

对象可以具有在多个线程中运行的代码.您的TThread.Create方法在调用它的线程的上下文中运行,这通常是您的主线程.Execute另一方面,该方法在创建的OS线程的上下文中运行.但很明显,这两种方法都可以访问TThread对象的字段,因此可以回答两个OS线程是否可以访问同一个变量的问题.

但是,您将无法以您描述的方式访问表单变量.将它作为var参数传递给构造函数将允许构造函数修改它,但正如我上面提到的,构造函数不会在新OS线程的上下文中运行.要允许新线程访问该变量,您需要存储指向它的指针,而不是通过引用传递它.例如:

type
  TSteveThread = class(TThread)
  private
    FVariable: PInteger;
  protected
    procedure Execute; override;
  public
    constructor Create(Variable: PInteger);
  end;

constructor TSteveThread.Create;
begin
  inherited Create(False);
  FVariable := Variable;
end;

procedure TSteveThread.Execute;
begin
  // Access FVariable^ here.
end;
Run Code Online (Sandbox Code Playgroud)

像这样创建它:

procedure TSteveForm.ButtonClick;
begin
  TSteveThread.Create(@Self.Variable);
end;
Run Code Online (Sandbox Code Playgroud)

另一种方法是将引用传递给表单,然后通过该引用访问表单的字段.例如:

type
  TSteveThread = class(TThread)
  private
    FForm: TSteveForm;
  protected
    procedure Execute; override;
  public
    constructor Create(Form: TSteveForm);
  end;

constructor TSteveThread.Create;
begin
  inherited Create(False);
  FForm := Form;
end;

procedure TSteveThread.Execute;
begin
  // Access FForm.Variable here.
end;
Run Code Online (Sandbox Code Playgroud)

像这样创建它:

procedure TSteveForm.ButtonClick;
begin
  TSteveThread.Create(Self);
end;
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,您都需要采取通常的预防措施来控制多个线程同时访问数据.底线是两个线程都可以访问数据.

  • 这是工作线程直接更改VCL主线程而没有任何保护.这就是造成竞争条件的原因.事实上,第一个例子也没有保护,例如关键部分. (2认同)