Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2008-09

TThread.WaitFor not returning?

8 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

I have a thread based logging framework (part of tiOPF). I created a "Log to GUI" viewer for the log framework using fpGUI toolkit. While the application runs, the cached logging to the GUI window works perfectly - no problems there. For some reason, the call to the internal TThread.WaitFor doesn't always return when the application terminates. The viewer is based on code for Delphi's VCL, which never showed this issue.

I'm not sure how to debug threads and don't have a clue as to what could cause the problem.

My application is built with FPC 2.2.3 and fpGUI toolkit, running under Ubuntu Linux 7.10 (2.6 based kernel).

Example of a successful termination:

./tutoradmin.exe -lv
TtiLogToGUI.FormClose called

> TfpgApplication.Destroy

destroying components... DONE
killing message queue
<< TfpgApplication.Destroy

> TtiLogToCacheAbs.Terminate

called .Terminate() and now calling .WaitFor()
<< TtiLogToCacheAbs.Terminate

An example, where the application doesn't terminate.

./tutoradmin.exe -lv
TtiLogToGUI.FormClose called

> TfpgApplication.Destroy

destroying components... DONE
killing message queue
<< TfpgApplication.Destroy

> TtiLogToCacheAbs.Terminate

called .Terminate() and now calling .WaitFor()

I have to press Ctrl+C to terminate the application fully.

TtiLogToCacheAbs is a abstract base class used for cached logging. It contains a TCriticalSection and a TThread.

TtiLogToGUI is a descendant of TtiLogToCacheAbs and contains the GUI Form instance (visual logging). The GUI Form is closed and destroyed before the Application or thread terminates. It's the first output line (....FormClose) shown above...

Here is the section of code which doesn't complete 100% and hangs the application when the application gets terminated.

procedure TtiLogToCacheAbs.Terminate;
begin
  writeln('>> TtiLogToCacheAbs.Terminate');
  FThrdLog.Terminate;
  writeln('   called .Terminate() and now calling .WaitFor()');
  FThrdLog.WaitFor;
  writeln('<< TtiLogToCacheAbs.Terminate');
end;

Any ideas?

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Luca Olivetti
to Graeme Geldenhuys

En/na Graeme Geldenhuys ha escrit:

Show quoted text 11 lines
procedure TtiLogToCacheAbs.Terminate; begin writeln('>> TtiLogToCacheAbs.Terminate'); FThrdLog.Terminate; writeln(' called .Terminate() and now calling .WaitFor()'); FThrdLog.WaitFor; writeln('<< TtiLogToCacheAbs.Terminate'); end; Any ideas?

Do you call synchronize inside the thread?
Anyway, I don't usually call WaitFor (I've had many problems with it), I set a flag in the thread and I loop sleeping (or calling checksynchronize if the thread uses synchronize) until it's true, eg:

procedure TMyThread.execute;
begin
   while not terminated do
   begin
     ....
   end;
   finished:=true;
end;
MyThread.Terminate;
while not MyThread.Finished do sleep(100);

or

while not MyThread.Finished do CheckSynchronize(100);

Bye

Luca

Reply by email

Unknown author
to Luca Olivetti

Hi!

I have a similar problem when using threads with synchronize... And I understand that threads in FPC/Lazarus under Linux/BSD works like this:

When you call synchronize from inside of you thread, this sends a message to application thread with the procedure that will be used to synchronize AND WAIT FOR a response from application thread of the execution of sync procedure. BUT when you call Thread.WaitFor in application thread, the application don't process any messages because it is waiting the thread finish, and thread don't finish because it is waiting a response of application thread of the execution of sync procedure... and you have your aplication freeze!

My solution in this case is override the WaitFor procedure...

procedure TMyThread.WaitFor;
begin
   while not ended do
      application.processmessages;
end;

...and var ended must be set to true in the last line of procedure execute...

Fabio Luis Girardi

2008/9/16 Luca Olivetti

Show quoted text 48 lines
En/na Graeme Geldenhuys ha escrit: > procedure TtiLogToCacheAbs.Terminate; > begin > writeln('>> TtiLogToCacheAbs.Terminate'); > FThrdLog.Terminate; > writeln(' called .Terminate() and now calling .WaitFor()'); > FThrdLog.WaitFor; > writeln('<< TtiLogToCacheAbs.Terminate'); > end; > > Any ideas? > Do you call synchronize inside the thread? Anyway, I don't usually call WaitFor (I've had many problems with it), I set a flag in the thread and I loop sleeping (or calling checksynchronize if the thread uses synchronize) until it's true, eg: procedure TMyThread.execute; begin while not terminated do begin .... end; finished:=true; end; MyThread.Terminate; while not MyThread.Finished do sleep(100); or while not MyThread.Finished do CheckSynchronize(100); Bye -- Luca _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Graeme Geldenhuys
to Unknown author
Show quoted text 8 lines
When you call synchronize from inside of you thread, this sends a message to application thread with the procedure that will be used to synchronize AND WAIT FOR a response from application thread of the execution of sync procedure. BUT when you call Thread.WaitFor in application thread, the application don't process any messages because it is waiting the thread finish, and thread don't finish because it is waiting a response of application thread of the execution of sync procedure... and you have your aplication freeze!

This is exactly what seems to be happening... I'll try your work-around and see how it goes. Thanks.

Note:
I have no such issues in Delphi, using the exact same threading code. So does that mean FPC has a bug in threading?

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Henry Vermaak
to Graeme Geldenhuys
Graeme Geldenhuys wrote 17 lines
On 9/17/08, wrote: > When you call synchronize from inside of you thread, this sends a message > to > application thread with the procedure that will be used to synchronize AND > WAIT FOR a response from application thread of the execution of sync > procedure. BUT when you call Thread.WaitFor in application thread, the > application don't process any messages because it is waiting the thread > finish, and thread don't finish because it is waiting a response of > application thread of the execution of sync procedure... and you have your > aplication freeze! This is exactly what seems to be happening... I'll try your work-around and see how it goes. Thanks. Note: I have no such issues in Delphi, using the exact same threading code. So does that mean FPC has a bug in threading?

Delphi has code in its WaitFor function that prevents this deadlock from occuring. They basically wait on the SyncEvent and the handle of the thread, calling CheckSynchonize when the SyncEvent triggers.

I'm not sure if this is possible with fpc, but I'm sure there must be a solution.

henry

Reply by email

Graeme Geldenhuys
to Henry Vermaak
Henry Vermaak wrote 7 lines
Delphi has code in its WaitFor function that prevents this deadlock from occuring. They basically wait on the SyncEvent and the handle of the thread, calling CheckSynchonize when the SyncEvent triggers. I'm not sure if this is possible with fpc, but I'm sure there must be a solution.

Umm, and TThread.WaitFor is not virtual, so I can't override it either. :-( I can't see any CheckSynchronize call in the unix implementation of TThread, so is might be a bug.

I'll raise this issue in the fpc-devel mailing list and see what they say. Thanks everybody for responding.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Michael Van Canneyt
to Graeme Geldenhuys
Graeme Geldenhuys wrote 15 lines
On 9/17/08, Henry Vermaak wrote: > > Delphi has code in its WaitFor function that prevents this deadlock > from occuring. They basically wait on the SyncEvent and the handle of > the thread, calling CheckSynchonize when the SyncEvent triggers. > > I'm not sure if this is possible with fpc, but I'm sure there must be > a solution. Umm, and TThread.WaitFor is not virtual, so I can't override it either. :-( I can't see any CheckSynchronize call in the unix implementation of TThread, so is might be a bug. I'll raise this issue in the fpc-devel mailing list and see what they say. Thanks everybody for responding.

CheckSynchronize must be called by the main thread on a regular basis in the event loop, so this is normal.

Michael.

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt
Michael Van Canneyt wrote
CheckSynchronize must be called by the main thread on a regular basis in the event loop, so this is normal.

CheckSynchronize is called in the main eventloop. This happens on application termination. The gLog singleton is freed in the finalization section of a unit. So maybe it's a timing issue? The main eventloop has already stopped functioning, by the time the gLog singleton is being free'd....

[...quickly testing...]

Umm, a quick test seems to reveal that might be the problem. As soon as the main form closes, the main eventloop stops as well - only then does the finalization section try to free the gLog singleton which contains the thread.

Freeing the gLog singleton in the main form's OnClose event, seems to resolve the issue.

How does this work in Lazarus? Do finalization code execute before the lazarus application's main eventloop terminates?

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email