开发者

How to avoid GUI freeze when calling Beginthread API?

Below just a simple race between 2 button in 2 threads,

and this will freeze other compo开发者_开发知识库nents 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;


The VCL (and parts of the RTL) is not thread-safe, so you cannot move components around from a thread. You have several options:

  • Use a 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.
  • Synchronize all VCL related stuff in the thread. TThread provides a static method Synchronize that does exactly that.
  • Send messages from the thread to the form using 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 EndThreadexplicitly when working with threads.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜