Search code examples
multithreadingdelphidelphi-2010

TThread.Execute is not called as expected


I am trying to display an activity indicating overlay (a spinning circle of dots) during a lengthy operation in my application. For this, i created a borderless transparent form with a TImage and an Imagelist, which i sought to update in a thread during the time the main thread is busy.

The problem i encountered is that the lengthy operation does not seem to get 'interupted' by my thread. The thread.Execute function loops a few times before the lengthy operation starts, and then again when the operation is finished.

It seems as if the thread is starved for some reason. I tried to raise it's priority, but could not see any effect.

Does anyone have similar experiences to share, or maybe even a solution?


Source code of thread function

procedure TIndicatorThread.Execute;
begin
  inherited;
  while(not Terminated) do
    begin
      fDlg.fCurindex := (fDlg.fCurindex+1) mod 12;
      Synchronize(UpdateImage);
      Application.ProcessMessages;
      sleep(80);
    end;
    Synchronize(fDlg.close);
    Synchronize(fDlg.Free);
end;

main thread

begin
[...]
myThread := TIndicatorThread.Create;
mythread.Resume;

Init_SomeUIRelatedstuff;
Application.ProcessMessages;

DoLengthyOperation; 

mythread.Terminate;

Solution

  • Your are doing the bulk of your thread work inside of Synchronize(), which delegates the work back to the main thread. If the main thread's lengthy operation is not processing new messages from the message queue, then Synchronize() has to wait. That is why your thread does not do anything while the lengthy operation is running.

    Your code is a poor example of how to use a thread effectively. What you should have done instead is perform the lengthy operation itself in the thread, and let the main thread handle the UI updates while the thread is running, eg:

    procedure TWorkThread.Execute; 
    begin 
      DoLengthyOperation;  
    end; 
    
    begin 
      ...
      Init_SomeUIRelatedstuff; 
      Application.ProcessMessages; 
    
      myThread := TWorkThread.Create(False);
      while WaitForSingleObject(myThread.Handle, 80) = WAIT_TIMEOUT do
      begin 
        fDlg.fCurindex := (fDlg.fCurindex+1) mod 12; 
        UpdateImage; 
        Application.ProcessMessages; 
      end; 
      mythread.Free;
    
      fDlg.Close; 
      fDlg.Free;
    
      ...
    end;