Sign in Join

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

Mailing lists / lazarus / 2011-09

Thread finalization

13 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

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

Leonardo M. Ramé

I'm having a rough time with Threads.

When my app starts, it creates an instance of a TThread that loads a bunch of images. That TThread instance can be destroyed in two ways:

1) When the loading finishes.
2) When the user closes the app while loading.

In case 2, I destroy the thread using this code:

  if Assigned(FMyThread) then
  begin
    FMyThread.Terminate;
    while not FMyThread.Finished do
      CheckSynchronize(100);
    FreeAndNil(FMyThread);
  end;

This works ok.

Now, in case 1, I thought that I should assign an OnTerminate event to the thread, then destroy it, but it doesn't work as expected. The app gets locked on my thread destroy event:

  procedure TForm1.Createthread;
  begin
    FMyThread := TMyThread.Create;
    FMyThread.OnTerminate := @ThreadDestroyEvent;
    FMyThread.Start;
  end;
  procedure TForm1.ThreadDestroyEvent(Sender: TObject);
  begin
    FMyThread.Free;
  end;
  destructor TMyThread.destroy;
  begin
    // destroy internal objects
    inherited destroy; // <-- The app gets locked here!!
  end;

Why is this happening?, am I doing something wrong?.

Reply by email

Sven Barth
to Leonardo M. Ramé
Leonardo M. Ram? wrote 44 lines
I'm having a rough time with Threads. When my app starts, it creates an instance of a TThread that loads a bunch of images. That TThread instance can be destroyed in two ways: 1) When the loading finishes. 2) When the user closes the app while loading. In case 2, I destroy the thread using this code: if Assigned(FMyThread) then begin FMyThread.Terminate; while not FMyThread.Finished do CheckSynchronize(100); FreeAndNil(FMyThread); end; This works ok. Now, in case 1, I thought that I should assign an OnTerminate event to the thread, then destroy it, but it doesn't work as expected. The app gets locked on my thread destroy event: procedure TForm1.Createthread; begin FMyThread := TMyThread.Create; FMyThread.OnTerminate := @ThreadDestroyEvent; FMyThread.Start; end; procedure TForm1.ThreadDestroyEvent(Sender: TObject); begin FMyThread.Free; end; destructor TMyThread.destroy; begin // destroy internal objects inherited destroy; //<-- The app gets locked here!! end; Why is this happening?, am I doing something wrong?.

I don't know whether this will solve your error, but two things of which I don't know whether they are known to you:
1. Calling "Terminate" will not kill the thread, it just sets the "Terminated" property to true, so you must check for yourself inside "Execute" whether your Thread should stop
2. The event you assigned to "OnTerminate" will only be called if you call "DoTerminate" inside the thread (the event will be called using Synchronize).

You might also want to take a look at the property "FreeOnTerminate" which tells the thread to free itself once "Execute" returns.

Regards,
Sven

Reply by email

Leonardo M. Ramé
to Sven Barth
Sven Barth wrote 60 lines
Am 21.09.2011 14:31, schrieb Leonardo M. Ram?: >I'm having a rough time with Threads. > >When my app starts, it creates an instance of a TThread that loads a >bunch of images. That TThread instance can be destroyed in two ways: > >1) When the loading finishes. >2) When the user closes the app while loading. > >In case 2, I destroy the thread using this code: > > if Assigned(FMyThread) then > begin > FMyThread.Terminate; > while not FMyThread.Finished do > CheckSynchronize(100); > FreeAndNil(FMyThread); > end; > >This works ok. > >Now, in case 1, I thought that I should assign an OnTerminate event to >the thread, then destroy it, but it doesn't work as expected. The app >gets locked on my thread destroy event: > > procedure TForm1.Createthread; > begin > FMyThread := TMyThread.Create; > FMyThread.OnTerminate := @ThreadDestroyEvent; > FMyThread.Start; > end; > > procedure TForm1.ThreadDestroyEvent(Sender: TObject); > begin > FMyThread.Free; > end; > > destructor TMyThread.destroy; > begin > // destroy internal objects > inherited destroy; //<-- The app gets locked here!! > end; > >Why is this happening?, am I doing something wrong?. > I don't know whether this will solve your error, but two things of which I don't know whether they are known to you: 1. Calling "Terminate" will not kill the thread, it just sets the "Terminated" property to true, so you must check for yourself inside "Execute" whether your Thread should stop 2. The event you assigned to "OnTerminate" will only be called if you call "DoTerminate" inside the thread (the event will be called using Synchronize). You might also want to take a look at the property "FreeOnTerminate" which tells the thread to free itself once "Execute" returns. Regards, Sven

Sven, the event OnTerminate is called. What's wrong is the destruction of the thread.

FreeOnTerminate is False. I don't want the thread to be destroyed automatically.

Reply by email

Zaher Dirkey
to Leonardo M. Ramé: I'm having a rough time with Threads. When my app starts, it creates an instance of a…
Leonardo M. Ram? wrote 8 lines
if Assigned(FMyThread) then begin FMyThread.Terminate; while not FMyThread.Finished do CheckSynchronize(100); FreeAndNil(FMyThread); end;
try
   FMyThread.Terminate;
   FMyThread.WaitFor;
....
Zaher Dirkey -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110921/ac3349df/attachment.html>

Reply by email

Leonardo M. Ramé
to Zaher Dirkey
Zaher Dirkey wrote 18 lines
On Wed, Sep 21, 2011 at 2:31 PM, Leonardo M. RamA(c) wrote: A if Assigned(FMyThread) then A begin A A FMyThread.Terminate; A A while not FMyThread.Finished do A A A CheckSynchronize(100); A A FreeAndNil(FMyThread); A end; try A A FMyThread.Terminate; A A FMyThread.WaitFor; ....A A A -- Zaher Dirkey

Zahker, using WaitFor blocks the app.

Also, as I said in the original post, that part is working ok.

Reply by email

cobines
to Leonardo M. Ramé: I'm having a rough time with Threads. When my app starts, it creates an instance of a…

Your thread calls OnTerminate via Synchronize and waits until the callback finishes. In the callback you call Thread.Destroy which waits until the thread finishes. It is a deadlock.

Other than using FreeOnTerminate=True, maybe periodically check from the main thread the status of the thread. If it is finished then destroy, but don't do it from OnTerminate.

cobines

Reply by email

Leonardo M. Ramé
to cobines
cobines wrote 11 lines
Your thread calls OnTerminate via Synchronize and waits until the callback finishes. In the callback you call Thread.Destroy which waits until the thread finishes. It is a deadlock. Other than using FreeOnTerminate=True, maybe periodically check from the main thread the status of the thread. If it is finished then destroy, but don't do it from OnTerminate. -- cobines

Well, the "best" way I found is to create a Timer that checks if the thread is terminated, then destroy it.

I don't like this. It would be better if the thread can communicate the main form that it has finished, then the main form can destroy it, without using a Timer.

Reply by email

Mattias Gaertner
to Leonardo M. Ramé
Show quoted text 8 lines
On 2011-09-21 15:38:08 +0200, cobines wrote: [...] Well, the "best" way I found is to create a Timer that checks if the thread is terminated, then destroy it. I don't like this. It would be better if the thread can communicate the main form that it has finished, then the main form can destroy it, without using a Timer.

Why must the main thread destroy it? The thread can destroy itself. Just add a Synchronize call in the destructor or at the end of Execute to let the main thread clear the references.

Mattias

Reply by email

Leonardo M. Ramé
to Mattias Gaertner
Mattias Gaertner wrote 17 lines
On Wed, 21 Sep 2011 11:12:12 -0300 Leonardo M. Ram? wrote: > On 2011-09-21 15:38:08 +0200, cobines wrote: >[...] > Well, the "best" way I found is to create a Timer that checks if the > thread is terminated, then destroy it. > > I don't like this. It would be better if the thread can communicate the > main form that it has finished, then the main form can destroy it, > without using a Timer. Why must the main thread destroy it? The thread can destroy itself. Just add a Synchronize call in the destructor or at the end of Execute to let the main thread clear the references. Mattias
So, you say that I should use FreeOnTerminate := true, and set MyThread
:= nil on the main thread?.

Reply by email

Mattias Gaertner
to Leonardo M. Ramé
Show quoted text 19 lines
On 2011-09-21 16:28:45 +0200, Mattias Gaertner wrote: > On Wed, 21 Sep 2011 11:12:12 -0300 > Leonardo M. Ram? wrote: > > > On 2011-09-21 15:38:08 +0200, cobines wrote: > >[...] > > Well, the "best" way I found is to create a Timer that checks if the > > thread is terminated, then destroy it. > > > > I don't like this. It would be better if the thread can communicate the > > main form that it has finished, then the main form can destroy it, > > without using a Timer. > > Why must the main thread destroy it? The thread can destroy itself. > Just add a Synchronize call in the destructor or at the end of Execute to let the main thread clear the references. > So, you say that I should use FreeOnTerminate := true, and set MyThread := nil on the main thread?.

Yes.

Mattias

Reply by email

Flávio Etrusco
to Mattias Gaertner: On Wed, 21 Sep 2011 11:12:12 -0300 Why must the main thread destroy it? The thread can…
Show quoted text 12 lines
On Wed, 21 Sep 2011 11:12:12 -0300 Leonardo M. Ram? wrote: > On 2011-09-21 15:38:08 +0200, cobines wrote: >[...] > Well, the "best" way I found is to create a Timer that checks if the > thread is terminated, then destroy it. > > I don't like this. It would be better if the thread can communicate the > main form that it has finished, then the main form can destroy it, > without using a Timer.

Would the attached example work for you?

-Fl?vio
-------------- next part --------------
A non-text attachment was scrubbed...
Name: threadtest.zip
Type: application/zip
Size: 4395 bytes
Desc: not available
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110921/c678f477/attachment.zip>

Reply by email

Zaher Dirkey
to Leonardo M. Ramé: Zahker, using WaitFor blocks the app. Also, as I said in the original post, that part is…
Leonardo M. Ram? wrote
Zahker, using WaitFor blocks the app.

Block the whole application or the current thread that run WaitFor? Example: Listener thread WaitFor Connection Thread.

Thanks

Zaher Dirkey
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110921/a3b78c13/attachment.html>

Reply by email

Frank Church
to Leonardo M. Ramé: So, you say that I should use FreeOnTerminate := true, and set MyThread := nil on the…
Leonardo M. Ram? wrote 32 lines
On 2011-09-21 16:28:45 +0200, Mattias Gaertner wrote: > On Wed, 21 Sep 2011 11:12:12 -0300 > Leonardo M. Ram? wrote: > > > On 2011-09-21 15:38:08 +0200, cobines wrote: > >[...] > > Well, the "best" way I found is to create a Timer that checks if the > > thread is terminated, then destroy it. > > > > I don't like this. It would be better if the thread can communicate the > > main form that it has finished, then the main form can destroy it, > > without using a Timer. > > Why must the main thread destroy it? The thread can destroy itself. > Just add a Synchronize call in the destructor or at the end of Execute to let the main thread clear the references. > > Mattias > So, you say that I should use FreeOnTerminate := true, and set MyThread := nil on the main thread?. -- Leonardo M. Ram? http://leonardorame.blogspot.com -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

How you found a way of resolving your problem?

I suspect I will be interested in this issue soon.

Frank Church ======================= http://devblog.brahmancreations.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20111004/ca358881/attachment.html>

Reply by email