Reputation: 1085
Below just a simple race between 2 button in 2 threads,
and this will freeze other components on the form.
procedure moveButton1();
var
I: Integer;
begin
for I := 0 to 6000 do
Form1.Button1.Left := Form1.Button1.Left - 1;
Form1.Caption := 'Button1 won!';
EndThread(0);
end;
procedure moveButton2();
var
I: Integer;
begin
for I := 0 to 6000 do
Form1.Button2.Left := Form1.Button2.Left - 1;
Form1.Caption := 'Button2 won!';
EndThread(0);
end;
procedure TForm1.Button3Click(Sender: TObject);
var
thread1, thread2,tick : Integer;
id1, id2 : LongWord;
begin
thread1 := BeginThread(nil,
0,
Addr(moveButton1),
nil,
0,
id1);
thread2 := BeginThread(nil,
0,
Addr(moveButton2),
nil,
0,
id2);
CloseHandle(thread1);
CloseHandle(thread2);
end;
Upvotes: 0
Views: 2122
Reputation: 53830
Using Synchronize() would be the down and dirty method of synchronizing the procedures that move the buttons. Synchronize() forces the method to be run in the main VCL thread. They'll block each other, so only one button can move at a time. This will avoid encountering non-thread safe code in the VCL.
I couldn't recreate the issue of the form freezing though, so I'm not sure that is your issue. You may wish to look elsewhere.
Upvotes: 0
Reputation: 16602
The VCL (and parts of the RTL) is not thread-safe, so you cannot move components around from a thread. You have several options:
TTimer
component. You don't need a thread and the timer's event handler will be executed in the context of the main thread. The timer was designed exactly for things like that.TThread
provides a static method Synchronize
that does exactly that.SendMessage
or PostMessage
and handle this message in the form.You might also consider to use the TThread
wrapper class instead of using BeginThread
and EndThread
explicitly when working with threads.
Upvotes: 10