Recent

Author Topic: Thread doesn't want to die  (Read 3270 times)

Tommi

  • Full Member
  • ***
  • Posts: 213
Thread doesn't want to die
« on: September 11, 2017, 02:13:22 pm »
I have a thread called elab.
Doing step by step debugging and using Ctrl-Alt-T thread window I see that after:
Quote
elab.free;
my thread is still alive.
So after some time there are too many threads and the application crashes.
The same with elab.destroy; or FreeAndNil(Elab);
When I try to free my thread it has already finished its execute function and I have just to read some variables and kill it.

Instead if I use the windows API:
Quote
     TerminateThread(Elab.Handle, 0);
     CloseHandle(Elab.Handle);
the threads are correctly destroyed and the application runs  but I have to disable debugger because it says that it cannot read PC registry.

How could I destroy a thread using lazarus functions?


marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Thread doesn't want to die
« Reply #1 on: September 11, 2017, 02:42:10 pm »
You can't.  Terminating threads is an emergency feature, and will result in an unstable process. (in any native language). So it is only meant to allow a partial graceful shutdown, not continue to run as if nothing happened.

the best thing is to make sure that the thead .EXECUTE method properly honors the terminate(d) property, and exits as fast as possible when it is set.

Tommi

  • Full Member
  • ***
  • Posts: 213
Re: Thread doesn't want to die
« Reply #2 on: September 11, 2017, 03:52:25 pm »
Execute function is finished, I am sure of this because I am trying to destroy the thread from the OnTerminate event.

I cannot use the properti freeOnTerminate because I have to read the reults of the computation before destroying the thread.

So how could I do ?
Here a piece of code similar to my approach:
Quote
global variables:
 elab:myThread;
 CrSz:TCriticalSection;

function myForm.startThread();
begin
 elab:=myThread.create(true);
 elab.parameter1:='hello';
 elab.parameter2:='hello2';
 elab.OnTerminate:=@onterm;
 CrSz:=TCriticalSection.Create;
 elab.criticalSection:=CrSz;
 elab.resume;
end;

procedure myForm.onterm(Sender: TObject);
begin
  jobDone:=elab.resultOfJob;
  elab.free;
 elab:=nil;
end;


If I use freeOnTerminate, I cannot see resultOfJob no more.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Thread doesn't want to die
« Reply #3 on: September 11, 2017, 04:07:44 pm »
Execute function is finished, I am sure of this because I am trying to destroy the thread from the OnTerminate event.

I cannot use the properti freeOnTerminate because I have to read the reults of the computation before destroying the thread.

Wrong. The thread is destroyed after your onTerminate event has finished executing if the FreeOnTerminate is set.

So how could I do ?
Here a piece of code similar to my approach:
Quote
global variables:
 elab:myThread;
 CrSz:TCriticalSection;

function myForm.startThread();
begin
 elab:=myThread.create(true);
 elab.parameter1:='hello';
 elab.parameter2:='hello2';
 elab.OnTerminate:=@onterm;
 CrSz:=TCriticalSection.Create;
 elab.criticalSection:=CrSz;
 elab.resume;
end;

procedure myForm.onterm(Sender: TObject);
begin
  jobDone:=elab.resultOfJob;
  elab.free;
 elab:=nil;
end;


If I use freeOnTerminate, I cannot see resultOfJob no more.
yes you can, but the code you shown so far, other than a problem with a critical section created for each thread and never destroyed, has no problem, that I can see, that should raise an exception. You either cut off to much or you have serious problems in your execute method. Post a small compile-able example that demonstrates you problem.[/quote]
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Tommi

  • Full Member
  • ***
  • Posts: 213
Re: Thread doesn't want to die
« Reply #4 on: September 11, 2017, 05:27:09 pm »
Here a minimal code to reproduce my problem:
Quote
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, SyncObjs;

type

  { TForm1 }

  TMyThread = class(TThread)
    var1:integer;
    var2:integer;
    done:integer;
    protected
      procedure Execute; override;
    public
      criticalS:TCriticalSection;
      Constructor Create(CreateSuspended : boolean);
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure onterm(Sender: TObject);
    procedure startAA;
  private
    { private declarations }
    criticalS:TCriticalSection;
  public
    { public declarations }
    aa:TMyThread;
  end;


var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  startAA;
end;

procedure TForm1.onterm(Sender: TObject);
begin
   criticalS.Acquire;
   form1.Caption:=inttostr(aa.done);
   criticalS.Release;
   criticalS.Free;
   aa.free;
   aa:=nil;
end;

procedure TForm1.startAA;
begin
   aa:=TMyThread.Create(true);
   criticalS:=TCriticalSection.Create;
   aa.criticalS:=criticalS;
   aa.var1:=4;
   aa.var2:=8;
   aa.OnTerminate:=@onterm;
   aa.Resume;
end;

Constructor TMyThread.Create(CreateSuspended : boolean);
begin
   inherited Create(CreateSuspended);
   FreeOnTerminate := False;
end;

procedure TMyThread.execute;
var
  temp:integer;
begin
  temp:=var1*var2;
  criticalS.Acquire;
  done:=temp;
  criticalS.Release;
end;

end.

When you press button1 the thread is launched. When it has done the result of its job is taken and used to change the caption.

But if you do Ctrl-Alt-T in the IDE you can see that the thread is not destroyed after Free command.

Instead if you replace aa.free with
Quote
   TerminateThread(aa.Handle, 0);
   CloseHandle(aa.Handle);

It works perfectly. (But often disturbs the debugger)
I would like use a lazarus command instead OS API, also because this solution is not os indipendent.
« Last Edit: September 11, 2017, 05:29:19 pm by Tommi »

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Thread doesn't want to die
« Reply #5 on: September 11, 2017, 05:33:46 pm »
Please note that OnTerminate event handler is executed in thread context, not in the main thread, so you can't access any LCL classes or functions from your event handler method.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Thread doesn't want to die
« Reply #6 on: September 11, 2017, 08:38:35 pm »
But if you do Ctrl-Alt-T in the IDE you can see that the thread is not destroyed after Free command.
Instead if you replace aa.free with
Quote
   TerminateThread(aa.Handle, 0);
   CloseHandle(aa.Handle);
It works perfectly. (But often disturbs the debugger)
See the answer @marcov earlier.
So, if you set FreeOnTerminate in your code and exclude aa.Free, then everything will work fine.

Please note that OnTerminate event handler is executed in thread context, not in the main thread, so you can't access any LCL classes or functions from your event handler method.
On which platform? In Windows, according to the documentation, it runs in the context of the main thread.


engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Thread doesn't want to die
« Reply #7 on: September 12, 2017, 01:44:41 am »
I am trying to destroy the thread from the OnTerminate event.
You should not destroy the thread while in the OnTerminate event.

I cannot use the properti freeOnTerminate because I have to read the reults of the computation before destroying the thread.
If you set FreeOnTerminate to True, you can still read the results in the OnTerminate event. OnTerminate event would be the last point you can touch the thread class before it gets destroyed.

Tommi

  • Full Member
  • ***
  • Posts: 213
Re: Thread doesn't want to die
« Reply #8 on: September 12, 2017, 12:33:18 pm »
Thank you very much guys, problem solved!

 

TinyPortal © 2005-2018