Recent

Author Topic: TThread questions  (Read 4176 times)

Birger52

  • Sr. Member
  • ****
  • Posts: 309
TThread questions
« on: May 17, 2019, 03:34:07 am »
2 actually.

Do I need to call Terminate, or does the thread terminate itself, when it is done with it's task?

In the examples, an event is realeased in the destroy method.
(http://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial)
Is this a problem in Pascal? Like it can cause memory leak in other programs, if an event is not freed from an object, before the objet is disposed?
Lazarus 2.0.8 FPC 3.0.4
Win7 64bit
Playing and learning - strictly for my own pleasure.

jamie

  • Hero Member
  • *****
  • Posts: 6091
Re: TThread questions
« Reply #1 on: May 17, 2019, 03:57:17 am »
I always call terminate.

You must remember to have your code within the thread monitoring the "terminated" Boolean..

 There is an option to set the thread to FreeOnTerminate but I never use that, I always use the manual way, it makes
me feel better.

 Call the "Terminate". Have your code within check the "Terminated" and if true, just exit the loop.

The only true wisdom is knowing you know nothing

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TThread questions
« Reply #2 on: May 17, 2019, 04:02:43 am »
Do I need to call Terminate, or does the thread terminate itself, when it is done with it's task?

No, the thread is "terminated" when its Execute method ends. You should only call Terminate to end the thread prematurely or when Execute loops until Thread.Terminated becomes True.

Quote
In the examples, an event is realeased in the destroy method.
(http://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial)
Is this a problem in Pascal? Like it can cause memory leak in other programs, if an event is not freed from an object, before the objet is disposed?

Huh? What do you mean? If you mean on the first(-ish) example, the form's OnDestroy event handler calls Thread.Terminate to: 1) end the thread, if it's running; and 2) incidentally, free the thread object (as explained, because the thread's FreeOnTerminate is set to True) It doesn't "release" any event.

A TThread is an object like any other object: if you create it somewhere you must make sure it's destroyed/freed somewhere else.

One way to do it is to set its FreeOnTerminate property to True: then it will auto-destroy after terminating.

Alternatively, if you set FreeOnTerminate to False, you must destroy it yourself somewhere: the form's OnDestroy handler is a good place but you can do it almost anywhere when you don't need it anymore.
« Last Edit: May 17, 2019, 04:12:26 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Birger52

  • Sr. Member
  • ****
  • Posts: 309
Re: TThread questions
« Reply #3 on: May 18, 2019, 12:21:49 am »
About the Event - it is section of Initialization and Finalization.
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyThread = class(TThread)
  3.   private
  4.     fRTLEvent: PRTLEvent;
  5.   public
  6.     procedure Create(SomeData: TSomeObject); override;
  7.     destructor Destroy; override;
  8.   end;
  9.  
  10. procedure TMyThread.Create(SomeData: TSomeObject; CreateSuspended: boolean);
  11. begin
  12.   // example: set up events, critical sections and other ressources like files or database connections
  13.   RTLEventCreate(fRTLEvent);
  14.   inherited Create(CreateSuspended);
  15. end;
  16.  
  17. destructor TMyThread.Destroy;
  18. begin
  19.   RTLeventDestroy(fRTLEvent);
  20.   inherited Destroy;
  21. end;

I am asking, because inC# it is nescessary to remove connection between object and event, as GC can remove the object.
Could be something similar - memory not being freed, or leftover pointers to nowhere...
Lazarus 2.0.8 FPC 3.0.4
Win7 64bit
Playing and learning - strictly for my own pleasure.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TThread questions
« Reply #4 on: May 18, 2019, 03:02:50 am »
Oh, that kind of event. Yes, a RTLEvent is a resource like any other: if you create it in one place you have to destroy elsewhere when it's no longer needed.

In FPC, RTL Events are just a synchronization mechanism, not directly related to objects. They're akin to semaphores and other such things.

In the example it's released in the OnDestroy handler because it's a handy place to do it, just as the OnCreate handler is a handy place to create it :)
« Last Edit: May 18, 2019, 03:05:27 am by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: TThread questions
« Reply #5 on: May 18, 2019, 07:09:17 am »
About the Event - it is section of Initialization and Finalization...
1. Create is a constructor, not a procedure.
2. The parameters of the method in the interface and the implementation must be the same.
3. The FPC does not have a garbage collector. Objects are explicitly destroyed (except for managed types). The destructor is called immediately, but not sometime in another thread by the garbage collector.

Birger52

  • Sr. Member
  • ****
  • Posts: 309
Re: TThread questions
« Reply #6 on: May 18, 2019, 02:47:26 pm »
:)
The not existing GB, is one of the reasons I prefer Pacal.

But the absence is not a guarantee against memory leaks.
So when I free an object, Events can still call none-existing handlers..
Lazarus 2.0.8 FPC 3.0.4
Win7 64bit
Playing and learning - strictly for my own pleasure.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TThread questions
« Reply #7 on: May 18, 2019, 03:30:48 pm »
So when I free an object, Events can still call none-existing handlers..

You're confusing the RTLEvent, which is basically just a signal, with "normal" control events: there are no "handlers" for a RTLEvent, just an opaque pointer and some functions to deal with it.

From the application's point of view all RTLEventCreate  does is something or other which returns an explicit pointer. That pointer is stored in a class field, but it may as welll be stored in a unit var or elsewhere. When you destroythe class, the pointer field is no longer accessible, but unitl you call RTLEventDestroy the RTLEvent's state is still valid and can still be accessed if you happened to store a copy of the pointer somewhere else.

Of course, if you didn't store a copy and you didn't call RTLEventDestroy before destroying the object, there is a memory leak and, maybe, some other resources locked, but nothing more serious than that ;)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Birger52

  • Sr. Member
  • ****
  • Posts: 309
Re: TThread questions
« Reply #8 on: May 20, 2019, 12:59:13 am »
OK - Thx.
Was looking into this RTLEvent stuff - but not really getting what it is about. Not much actual documentation on how to use it.
I figure it is manly for messaging across Threads.

I use regular events for my needs (at the moment, anyway).
Lazarus 2.0.8 FPC 3.0.4
Win7 64bit
Playing and learning - strictly for my own pleasure.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TThread questions
« Reply #9 on: May 20, 2019, 03:07:47 am »
Not much actual documentation on how to use it.
I figure it is manly for messaging across Threads.

Yes, it's meant for thread signalling/synchronization. There is some minimal documentation in the wiki, in the page about Threads.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

kveroneau

  • Full Member
  • ***
  • Posts: 119
Re: TThread questions
« Reply #10 on: June 04, 2019, 05:07:28 pm »
I wrote the most simplest TThread program for personal notes, this is a command-line example as it is the easiest to understand what's going on.  If you use threads in a GUI program you do not need to call CheckSynchronize.  http://tech406.com/kdocs/threads.xml

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TThread questions
« Reply #11 on: June 04, 2019, 06:06:22 pm »
I wrote the most simplest TThread program for personal notes, this is a command-line example as it is the easiest to understand what's going on.  If you use threads in a GUI program you do not need to call CheckSynchronize.  http://tech406.com/kdocs/threads.xml

Your code touches the thread outside SayHello:
Code: Pascal  [Select][+][-]
  1. uses mythread;
  2.  
  3. var
  4.   t: TMyThread;
  5. begin
  6.   t:=TMyThread.Create;
  7.   t.Start;
  8.   WriteLn('Thread started.');
  9.   repeat
  10.     Sleep(1500);
  11.     WriteLn('Checking sync...');
  12.     CheckSynchronize();
  13.   until t.Finished;
  14. end.

It should not.

kveroneau

  • Full Member
  • ***
  • Posts: 119
Re: TThread questions
« Reply #12 on: June 04, 2019, 08:06:14 pm »
Your code touches the thread outside SayHello:
What is the recommended way of checking outside a thread of a thread has finished?  I will update my personal notes to reflect this.

Looking at the source code for TThread.WaitFor which is referenced as being called from the main thread in an example in http://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial WaitFor which runs outside the thread uses the following code:

Code: Pascal  [Select][+][-]
  1. function TThread.WaitFor: Integer;
  2. begin
  3.   WRITE_DEBUG('waiting for thread ',ptruint(FHandle));
  4.   If (MainThreadID=GetCurrentThreadID) then
  5.     {
  6.      FFinished is set after DoTerminate, which does a synchronize of OnTerminate,
  7.      so make sure synchronize works (or indeed any other synchronize that may be
  8.      in progress)
  9.     }
  10.     While not FFinished do  
  11.       CheckSynchronize(100);
  12.   WaitFor := WaitForThreadTerminate(FHandle, 0);
  13.   { should actually check for errors in WaitForThreadTerminate, but no }
  14.   { error api is defined for that function                             }
  15.   FThreadReaped:=true;
  16.   WRITE_DEBUG('thread terminated');
  17. end;
  18.  

This implies that it should be fine for regular code outside of the thread to read the .Finished property with no worries.  In fact, WaitFor does almost the exact same thing as my code, expect in my code I use a repeat/until instead of a while-loop.  Source reference:  rtl/unix/tthread.inc

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: TThread questions
« Reply #13 on: June 04, 2019, 08:56:59 pm »
Sorry, I should have explained more. The problem is not with calling Finished, it is the fact that you used:
Code: Pascal  [Select][+][-]
  1.   FreeOnTerminate:=True;

To be more precise, this part of your code runs in the main thread:
Code: Pascal  [Select][+][-]
  1.     CheckSynchronize();
  2.   until t.Finished;

If TMyThread frees itself after the main thread has finished with CheckSynchronize, and before the check t.Finished, t would be invalid.

The order in this case is equivalent to:
Code: Pascal  [Select][+][-]
  1.   t.Free;   //<---- called in TMyThread
  2.   t.Finished;   //<---- called in the main thread

A better way is to avoid using FreeOnTerminate:=True, and to free the thread yourself after the check t.Finished.


By the way, WriteLn is not thread safe. In a real situation you'll get lines form different threads mangled.
« Last Edit: June 04, 2019, 09:03:02 pm by engkin »

kveroneau

  • Full Member
  • ***
  • Posts: 119
Re: TThread questions
« Reply #14 on: June 04, 2019, 09:30:15 pm »
Sorry, I should have explained more. The problem is not with calling Finished, it is the fact that you used:
Code: Pascal  [Select][+][-]
  1.   FreeOnTerminate:=True;
Ah, thank you so much for the clarification.  That makes complete sense now.  I will update the example code in my documentation to reflect the FreeOnTerminate change, and manually Free the thread.

I will also make mention that using WriteLn in this example is solely for example purposes to show the thread starting, running, and stopping.  I had a hunch WriteLn wasn't thread-safe, as stdout does mangle in Python if used within a thread as well.  WriteLn should only be called from the main thread.

 

TinyPortal © 2005-2018