Reputation: 15
I need my Thread
work independent of Form
.
For example I have a endless loop in my Thread
:
procedure TCustomThread.doProc;
begin
repeat
.
.
.
until (1 = 2);
end;
procedure TCustomThread.Execute;
begin
inherited;
Synchronize(doProc);
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
var
thrd : TCustomThread;
begin
thrd := TCustomThread.Create(True);
thrd.Resume;
Application.ProcessMessages;
end;
Now, when I click on Button1
, my Thread
runs but main Form
is locked. How can I avoid suspending Form
?
Upvotes: 2
Views: 829
Reputation: 596557
TThread.Synchronize()
runs the specified procedure in the context of the main thread, not in the context of the worker thread. So your loop is running in the main thread and is not letting hte main thread process new messages from its message queue. That is why your UI is not responding while your thread is running.
You need to restructure your thread to something more like this:
procedure TCustomThread.doUpdateUI;
begin
... do something that updates the UI here ...
end;
procedure TCustomThread.Execute;
begin
while not Terminated do
begin
... do something in the worker thread ...
Synchronize(doUpdateUI);
... do something else in the worker thread ...
end;
end;
var
thrd : TCustomThread = nil;
procedure TForm1.Button1Click(Sender: TObject);
begin
if thrd = nil then
thrd := TCustomThread.Create(False);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if thrd <> nil then
begin
thrd.Terminate;
thrd.WaitFor;
FreeAndNil(thrd);
end;
end;
Upvotes: 0
Reputation: 613013
The call to ProcessMessages
is wrong and should be removed. As a broad and general rule, calls to ProcessMessages
should be avoided. And this one serves no purpose at all.
The rest of your code simply runs a non-terminating loop. It does so using Synchronize
which ensures that the non-terminating loop runs on the main thread. Hence the main thread is unable to service its message loop.
The entire purpose of threads is to be able to execute separate threads of execution. By using Synchronize
you are running all your code in the main thread. Your code is equivalent to placing the non-terminating loop in the main thread.
You want to execute code in a different thread. So you should avoid the call to Synchronize
. That should only be used for small, quick pieces of work that must execute on the main thread. Typically GUI updates.
Your execute method should be:
procedure TCustomThread.Execute;
begin
while not Terminated do
begin
....
end;
end;
This introduces your loop, but the loop now executes in the thread. You can now add the useful code of your thread inside the body of the loop.
Remember that any use of VCL components must happen on the main thread. And that's where Synchronize
is to be used.
Upvotes: 9