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;
В любом случае вам необходимо принять обычные меры предосторожности при управлении одновременным доступом к данным несколькими потоками. Суть в том, что оба потока могут получить доступ к данным.