Recent

Author Topic: Playing with thread, memory leaks  (Read 38420 times)

Fred vS

  • Hero Member
  • *****
  • Posts: 1675
    • miXimum is the DJ's best friend
Re: Playing with thread, memory leaks
« Reply #15 on: February 16, 2014, 10:15:53 pm »
Quote
The complexity lies in the fact that you must make sure the thread has not yet freed itself yet, when you call Waitfor.

Yep, that is the Big problem of Threads and array of Threads.

You cannot know if the thread has terminated, even with
Code: [Select]
if assisgned(MyTreads[x]).
It is the reason why i use a "twins" array of shortint, who vary in length with ThreadArray.

Code: [Select]
If MyTreads[x].create() then  MyArrayShortint[x] := 1.
If MyTreads[x].terminate  then  MyArrayShortint[x] := -1.

And, before to try to free a member of array, i check
Code: [Select]
if MyArrayShortint[x] = 1 then  MyArrayTreads[x].free....
« Last Edit: February 16, 2014, 10:25:35 pm by Fred vS »
I use Lazarus 1.8.0 32/64 and FPC 3.0.3 32/64 on Linux Mint Mate 17 32/64, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #16 on: February 16, 2014, 10:26:40 pm »
And, before to try to free a member of array, i check
Code: [Select]
if MyArrayShortint[x]...
How do you know that the execution will not shift to the thread you are trying to free exactly after it passed this check.

Fred vS

  • Hero Member
  • *****
  • Posts: 1675
    • miXimum is the DJ's best friend
Re: Playing with thread, memory leaks
« Reply #17 on: February 16, 2014, 10:38:56 pm »
Quote
How do you know that the execution will not shift to the thread you are trying to free exactly after it passed this check.

This is to check mainly if the thread.create has append.

After that , because in the Thread-class there is :

Code: [Select]
TMyThread = class(TThread)
  protected
    procedure Execute; override;
  public
    isterminated :booelan;  ====> this one
     constructor Create(CreateSuspended: boolean);
    destructor Destroy; override;
  end;

And in thread.execute :

Code: [Select]
procedure TMyThread.Execute;
begin
  repeat
    Sleep(60);
until terminated_var = True;
 isterminated := true; ===> here
terminate;
end,
end;

If the thread was created, i can check isterminated even if thread has terminated (and so free the thread if needed)
« Last Edit: February 16, 2014, 10:43:06 pm by Fred vS »
I use Lazarus 1.8.0 32/64 and FPC 3.0.3 32/64 on Linux Mint Mate 17 32/64, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

eny

  • Hero Member
  • *****
  • Posts: 1587
Re: Playing with thread, memory leaks
« Reply #18 on: February 16, 2014, 10:50:15 pm »
As you can see it calls Terminate and WaitFor. Maybe you have some specific objection to using FreeAndNil on a TThread?
My objection is that the program will crash horribly when calling FreeAndNil on a running thread.
Try the simple example TS gave and instead of terminate/waifor, call FreeAndNil.
Could be related to the usage of sleep though.
« Last Edit: February 16, 2014, 10:52:30 pm by eny »
All posts based on: Win10 (Win64); Lazarus 1.8.0 'stable' (#56594 win64) unless specified otherwise...

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #19 on: February 16, 2014, 11:37:22 pm »
@eny, LOL I see your objection clearly.

@Fred, Thanks.

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #20 on: February 17, 2014, 12:44:27 am »
My objection is that the program will crash horribly when calling FreeAndNil on a running thread.
It seems to me that having FreeOnTerminate = true caused the crash after calling FreeAndNil.

Try the simple example TS gave and instead of terminate/waifor, call FreeAndNil.
Could be related to the usage of sleep though.
Could you change his TMyThread.Create to make sure FreeOnTerminate := False and check again.

Fred vS

  • Hero Member
  • *****
  • Posts: 1675
    • miXimum is the DJ's best friend
Re: Playing with thread, memory leaks
« Reply #21 on: February 17, 2014, 01:03:35 am »
@ engkin :
Quote
if t <> nil then
    T.Terminate;

Code: [Select]
if t <> nil Is not really useful, =>will always be true.

Also, if the thread was not created,
Code: [Select]
if t <> nil then
    T.Terminate;
Will give a error and a big boum.  :-X
« Last Edit: February 17, 2014, 01:16:34 am by Fred vS »
I use Lazarus 1.8.0 32/64 and FPC 3.0.3 32/64 on Linux Mint Mate 17 32/64, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #22 on: February 17, 2014, 01:44:30 am »
Code: [Select]
if t <> nil Is not really useful, =>will always be true.
Not if someone used FreeAndNil(t) or initialized t to nil in the form constructor. But again, I'm wondering about problems related to using FreeAndNil to terminate a thread gracefully. I did notice that I can not use it when FreeOnTerminate is true.

eny

  • Hero Member
  • *****
  • Posts: 1587
Re: Playing with thread, memory leaks
« Reply #23 on: February 17, 2014, 06:58:21 pm »
..or initialized t to nil in the form constructor...
I have read somewhere that instance variables (e.g. form variables) are initialized to zero (the object instance is filled with zeroes via a call to fillchar).
This is however not documented in the expected location (http://www.freepascal.org/docs-html/ref/refse32.html#x71-810006.2).
All posts based on: Win10 (Win64); Lazarus 1.8.0 'stable' (#56594 win64) unless specified otherwise...

Blestan

  • Sr. Member
  • ****
  • Posts: 461
Re: Playing with thread, memory leaks
« Reply #24 on: February 17, 2014, 08:10:32 pm »
it's a bad idea or even impossible ( on linux or some others unices)  to terminate  a thread from another thread ...
do not forget that the pascal TThreadd class is just a warper around  OS ( or lib functions) ... the thread main function is passed to the  OS like a callback and executed in new thread ... the only way to terfinate a thread. gracefully is to check in the execute method  periodicly for. the  terminated property .... and just exit the function ASAP ... using free or freeandnil will just free the warper object and will create a complete mess!
Speak postscript or die!
Translate to pdf and live!

howardpc

  • Hero Member
  • *****
  • Posts: 3183
Re: Playing with thread, memory leaks
« Reply #25 on: February 17, 2014, 08:16:23 pm »
I have read somewhere that instance variables (e.g. form variables) are initialized to zero

I don't know where it can be found in the documentation, but in an fpc mailing list message (28/11/12) Jonas confirmed that global variables and static global arrays are always initialized to zero.

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #26 on: February 17, 2014, 11:56:01 pm »
... using free or freeandnil will just free the warper object and will create a complete mess!
Please correct me if I'm wrong. As long as FreeOnTerminate = false it is perfectly OK to use Free or FreeAndNil, and here is why:

When you call Free (or FreeAndNil) it calls Destroy:
Quote from: rtl\inc\objpas.inc
      procedure TObject.Free;
        begin
           // the call via self avoids a warning
           if self<>nil then
             self.destroy;
        end;

Destroy calls SysDestroy before it frees the object:
Quote from: rtl\objpas\classes\classes.inc
destructor TThread.Destroy;
begin
  if not FExternalThread or False then begin
    SysDestroy;
..
  inherited Destroy;
end;

SysDestroy, on Windows, terminates the thread gracefully. It makes sure it's not finished, if not it calls terminate and then WaitFor.
Quote from: rtl\win\tthread.inc
procedure TThread.SysDestroy;
begin
  if FHandle<>0 then
    begin
      { Don't check Suspended. If the thread has been externally suspended (which is
        deprecated and strongly discouraged), it's better to deadlock here than
        to silently free the object and leave OS resources leaked. }
      if not FFinished {and not Suspended} then
        begin
          Terminate;
          { Allow the thread function to perform the necessary cleanup. Since
            we've just set Terminated flag, it won't call Execute. }
          if FInitialSuspended then
            Start;
          WaitFor;
        end;
    end;

  FFatalException.Free;
  FFatalException := nil;
end;

SysDestroy, on Linux, does the same thing in a better way, in my opinion:
Quote from: rtl\unix\tthread.inc
procedure TThread.SysDestroy;
begin
..
      // if someone calls .Free on a thread with not(FreeOnTerminate), there
      // is no problem. Otherwise, FreeOnTerminate must be set to false so
      // when ThreadFunc exits the main runloop, it does not try to Free
      // itself again
      FFreeOnTerminate := false;
      { you can't join yourself, so only for FThreadID<>GetCurrentThreadID }
      { and you can't join twice -> make sure we didn't join already       }
      if not FThreadReaped then
        begin
          Terminate;
          if (FSuspendedInternal or FInitialSuspended) then
            Resume;
          WaitFor;
        end;
    end;
  CurrentTM.SemaphoreDestroy(FSem);
..
end;

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #27 on: February 18, 2014, 12:09:56 am »
I have read somewhere that instance variables (e.g. form variables) are initialized to zero (the object instance is filled with zeroes via a call to fillchar).
I confirm seeing that in the source code:
rtl\inc\objpas.inc
Code: [Select]
      class function TObject.InitInstance(instance : pointer) : tobject; {$ifdef SYSTEMINLINE} inline; {$ENDIF}
        begin
           { the size is saved at offset 0 }
           fillchar(instance^, InstanceSize, 0);
...
        end;

Blestan

  • Sr. Member
  • ****
  • Posts: 461
Re: Playing with thread, memory leaks
« Reply #28 on: February 18, 2014, 01:43:01 pm »
@ engkin :
when you call a method of TThread Instance it's executed in the current context NOT in the thread!!!
i repeat once more the TThread Class is just a wapper around OS or lib (dll) function that actually manages the threads on the computer.
the thread are NOT pascal objects that you can manage ... freeandnil, destroy and free just deallocates the memory in the heap and runs some cleanup in the pascal hierarchy of classes... they cannot terminate a running.
an OS thread terminates by exiting its main proc.
thread all the methods must be called within the thread it self.. the code that you  quoted is just fine if called from the thread it self..
So, you cannot terminate the thread from another thread
« Last Edit: February 18, 2014, 01:48:11 pm by Blestan »
Speak postscript or die!
Translate to pdf and live!

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Playing with thread, memory leaks
« Reply #29 on: February 18, 2014, 03:00:45 pm »
@ engkin :
when you call a method of TThread Instance it's executed in the current context NOT in the thread!!!
I agree with that. Where did you see me claiming the opposite?

i repeat once more the TThread Class is just a wapper around OS or lib (dll) function that actually manages the threads on the computer.
I agree with this one as well.

the thread are NOT pascal objects that you can manage ...
Hmmm, it depends on what you mean by "manage".

freeandnil, destroy and free just deallocates the memory in the heap and runs some cleanup in the pascal hierarchy of classes...
Obviously you did not read the source code I quoted above. FreeAndNil, Free, and Destroy do wait for the thread to terminate itself (by exiting its Execute method) before deallocating the memory in the heap and running cleanup code.

they cannot terminate a running. an OS thread terminates by exiting its main proc.
Hopefully that happens when it checks its FTerminated which holds the value True after we call Terminate, Free, FreeAndNil, or Destroy from another thread.

thread all the methods must be called within the thread it self.. the code that you  quoted is just fine if called from the thread it self..
So, you cannot terminate the thread from another thread
Just to be precise, you can call any of these methods from another thread, and yes they do not terminate the thread. They simply indicate that the thread needs to terminate itself by setting FTerminated to true and then they wait for it to happen using WaitFor.