Alex
Alex

Reputation: 11

Multithreaded Delphi 7 App - a problem with app termination

I have a descendent of TThread and a list of objects, each with its own copy of such thread and yet the Event object, created with CreateEvent() API.

Different objects interact with each other by event firing. I.e. each thread must wait until some other thread will fire its event. Of course, there is one "master" thread, which works permanently, so self-blocking could never happen. This system works just fine upto the end of the Execute method in each object.

The probkem appears when I'm trying to interrupt all threads, e.g. by app closing. In this case I need some external function which calls Terminate method of each thread:

  for i := 0 to FLayers.Count - 1 do
  begin
    FLayers.Layer[i].FTerminating := true;
    f := true;
    while f do
    begin
      f := FLayers.Layer[i].IsActive;
      if f then
      begin
        Sleep(100);
        Application.ProcessMessages;
      end;
    end;
    FLayers.Layer[i].FTerminating := false;
  end;

This function sits in Form.OnClose() event.

The problem is that about two of threads are terminated normally, but other all are stopped at the WaitForSingleObject() call:

procedure TLayerThread.Execute;
begin
FLayer.FIsActive := true;
...............
repeat
 //
 if Terminated or
   FLayer.FTerminating or
   (FLayer.FEvent = INVALID_HANDLE_VALUE) then
   begin
     break;
   end;
 //
 Fres := WaitForSingleObject(FLayer.FEvent, 100); <<<<<<<<<<<<<<<<<<<<<<<<
until Fres <> WAIT_TIMEOUT;
...........
FLayer.FIsActive := false;
end;

All the threads are just stopped (hang) at the line. marked above, despite the timeout value is set.

Any ideas?

Am using Delphi 7 and Win XP.

Thanks in advance.

Followup--

I've found that the problem is covered in the Synchronize() call from within the Execute() method. I can't understand what is wrong here. Synchronize() calls usual things like visual controls update and nothing more.

As debugger shows, nost of my threads are hanging on some WaitForSingleObject() call, but this is not what I use in the Execute() method to coordinate different threads, but some another call. I can suppose that it is here:

class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
.................
        LeaveCriticalSection(ThreadLock);
        try
          WaitForSingleObject(SyncProc.Signal, INFINITE);<<<<<<<<<<<<<<<<<<<<<<
        finally
          EnterCriticalSection(ThreadLock);
        end;
..................

Is there anybody out there, who could tell me what is wrong in my code? I never heard that it is not allowed to call Synchronize() from within Execute() method...

Upvotes: 1

Views: 1075

Answers (1)

Robert
Robert

Reputation: 42585

Instead of WaitForSingleObject you should use WaitForMultipleObjects with infinite timeout and waiting two events, your FLayer.FEvent and a second termination-event.

AFAIR you have to create one termination-event per process. If WaitForMultipleObjects returns the ID of the termination-event exit the loop.

In the OnClose() method you simple have to signal all termination-events.

Upvotes: 1

Related Questions