Using: Delphi XE2, Windows VCL Forms application
Can a TThread during its execution change the value of a variable in the main VCL thread?
The need is to update an Integer which is declared as a field of the TForm class. It will be passed to the TThread as a var variable in an overloaded (and reintroduce) Create constructor method.
Are there any fallbacks in this?
Yes, threads can modify variables. Variables don't belong to threads. Variables can belong to form or thread objects, but a thread object (i.e., an instance of TThread
or its descendants) is distinct from the OS execution thread.
Objects can have code that runs in multiple threads. Your TThread.Create
method runs in the context of the thread that calls it, which is often your main thread. The Execute
method, on the other hand, runs in the context of the created OS thread. But obviously, both methods can access the fields of the TThread
object, so that answers the question of whether two OS threads can access the same variable.
You'll have trouble accessing the form variable in the way you describe, though. Passing it to the constructor as a var parameter will allow the constructor to modify it, but as I mentioned above, the constructor doesn't run in the context of the new OS thread. To allow the new thread to access that variable, you'd need to store a pointer to it instead of passing it by reference. For example:
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;
Create it like this:
procedure TSteveForm.ButtonClick;
begin
TSteveThread.Create(@Self.Variable);
end;
An alternative is to pass a reference to the form instead, and then access the form's field through that reference. For example:
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;
Create it like this:
procedure TSteveForm.ButtonClick;
begin
TSteveThread.Create(Self);
end;
In either case, you need to take the usual precautions about controlling simultaneous access to the data by multiple threads. The bottom line is that both threads can access the data.