Delphi - Может ли TThread изменить значение переменной в основном потоке VCL?

Использование: Delphi XE2, приложение Windows VCL Forms.

Может ли TThread во время своего выполнения изменить значение переменной в основном потоке VCL?

Необходимо обновить Integer, который объявлен как поле класса TForm. Он будет передан в TThread как переменная var в перегруженном (и повторно введенном) методе конструктора Create.

Есть ли в этом какие-то недостатки?

1 ответ

Решение

Да, потоки могут изменять переменные. Переменные не принадлежат потокам. Переменные могут принадлежать объектам формы или потока, но объект потока (т. Е. Экземпляр TThread или его потомков) отличается от потока выполнения ОС.

Объекты могут иметь код, который выполняется в нескольких потоках. Ваш TThread.Create Метод выполняется в контексте вызывающего его потока, который часто является вашим основным потоком. Execute метод, с другой стороны, выполняется в контексте созданного потока ОС. Но очевидно, что оба метода могут получить доступ к полям TThread объект, так что отвечает на вопрос, могут ли два потока ОС получить доступ к одной и той же переменной.

У вас будут проблемы с доступом к переменной формы, как вы описываете. Передача его конструктору в качестве параметра var позволит конструктору изменить его, но, как я упоминал выше, конструктор не запускается в контексте нового потока ОС. Чтобы позволить новому потоку получить доступ к этой переменной, вам нужно сохранить указатель на нее, а не передавать его по ссылке. Например:

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;

Создайте это так:

procedure TSteveForm.ButtonClick;
begin
  TSteveThread.Create(@Self.Variable);
end;

Альтернатива - вместо этого передать ссылку на форму, а затем получить доступ к полю формы через эту ссылку. Например:

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;

Создайте это так:

procedure TSteveForm.ButtonClick;
begin
  TSteveThread.Create(Self);
end;

В любом случае вам необходимо принять обычные меры предосторожности при управлении одновременным доступом к данным несколькими потоками. Суть в том, что оба потока могут получить доступ к данным.

Другие вопросы по тегам