Recent

Author Topic: [SOLVED] Error class 'external : SIGSEGV' when running Thread  (Read 1763 times)

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Error class 'external : SIGSEGV' when running Thread
« Reply #15 on: June 17, 2019, 01:42:34 pm »
I would still use the constructor, but like so:
Code: Pascal  [Select]
  1. procedure TMainFrm.Go();
  2. var
  3.   Dt5 : TD3GetDtThr;
  4. begin
  5.   Dt5 := TD3GetDtThr.Create(false);
  6. end;    
  7.  
  8. constructor TD3GetDtThr.Create(CreateSuspended: boolean); // Set to true or false, see below
  9. begin
  10.   inherited Create(true); // Always call inherited first. MUST be true, so you can also set it directly to true here
  11.   FreeOnTerminate := True;
  12.   Dt5.OnTerminate:= @ThreadDone; // Can do that here
  13.  If CreateSuspended = false then Start;  // Now it starts  immediately after setup if CreateSuspended = false and manually when true
  14. end;  
     
How would you reach a local variable Dt5 in TMainFrm.Go() from TD3GetDtThr.Create() ?????????????

Anyway, I wouldn't use any hard variable inside TD3GetDtThr because you can't use TD3GetDtThr anywhere else then.

If you really want to, you could override the TD3GetDtThr.Create and pass the ThreadDone as parameter.
« Last Edit: June 17, 2019, 01:47:55 pm by rvk »

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #16 on: June 17, 2019, 01:47:25 pm »
Yes, I overlooked that. That's the third mistake in the code.
It should be a form variable or better a global.
Local thread variables are not a good idea.... ;D :( They are not longer accessible after the method exits and can lead to side effects even if the thread is still running.
« Last Edit: June 17, 2019, 01:50:22 pm by Thaddy »
also related to equus asinus.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #17 on: June 17, 2019, 01:48:56 pm »
B.T.W. does inherited Create(false); really start the thread right away?
According to me it waits until the construction is finished.
So you can just do inherited Create(CreateSuspended); in that constructor and remove the Start at the end.
Execute won't run before the constructor is finished, does it?

(bug in the wiki?)

Code: Pascal  [Select]
  1. constructor TD3GetDtThr.Create(CreateSuspended: boolean); // Set to true or false, see below
  2. begin
  3.   inherited Create(CreateSuspended); // no need to start it paused, is there??
  4.   FreeOnTerminate := True;
  5.  
  6.   // do some other initializing...
  7.  
  8.   // If CreateSuspended = false then Start;when true
  9. end;  
     
« Last Edit: June 17, 2019, 01:50:43 pm by rvk »

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #18 on: June 17, 2019, 01:52:59 pm »
I consider that implementation detail, but inherited create(false) will finish so the thread should be running at that point.
In Delphi we had all kinds of problems because of that. I am not sure about the details for FPC.
My approach is at least a safe approach.
also related to equus asinus.

incendio

  • Jr. Member
  • **
  • Posts: 92
Re: Error class 'external : SIGSEGV' when running Thread
« Reply #19 on: June 17, 2019, 02:06:37 pm »
I would still use the constructor, but like so:
Code: Pascal  [Select]
  1. procedure TMainFrm.Go();
  2. var
  3.   Dt5 : TD3GetDtThr;
  4. begin
  5.   Dt5 := TD3GetDtThr.Create(false);
  6. end;    
  7.  
  8. constructor TD3GetDtThr.Create(CreateSuspended: boolean); // Set to true or false, see below
  9. begin
  10.   inherited Create(true); // Always call inherited first. MUST be true, so you can also set it directly to true here
  11.   FreeOnTerminate := True;
  12.   Dt5.OnTerminate:= @ThreadDone; // Can do that here
  13.  If CreateSuspended = false then Start;  // Now it starts  immediately after setup if CreateSuspended = false and manually when true
  14. end;  
     
How would you reach a local variable Dt5 in TMainFrm.Go() from TD3GetDtThr.Create() ?????????????

Anyway, I wouldn't use any hard variable inside TD3GetDtThr because you can't use TD3GetDtThr anywhere else then.

If you really want to, you could override the TD3GetDtThr.Create and pass the ThreadDone as parameter.
You were right. Dt5 variable won't recognised on thread create procedure.

So, back to old code then, without constructor.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #20 on: June 17, 2019, 02:13:16 pm »
I consider that implementation detail, but inherited create(false) will finish so the thread should be running at that point.
In Delphi we had all kinds of problems because of that. I am not sure about the details for FPC.
My approach is at least a safe approach.
The thread might be created and running but I don't think the Execute will run before the constructor is finished.
But you are correct, that could be en implementation detail which might not be exactly be implemented as I described so your approach will be indeed the safest course.

So, back to old code then, without constructor.
So, do something like this:

Code: Pascal  [Select]
  1. type
  2.   TD3GetDtThr = class(TThread)
  3.   protected
  4.     procedure Execute; override;
  5.   public
  6.     constructor Create(CreateSuspended: boolean; AThreadDone: TNotifyEvent); reintroduce; overload;
  7.   end;
  8.  
  9. constructor TD3GetDtThr.Create(CreateSuspended: boolean; AThreadDone: TNotifyEvent);
  10. begin
  11.   inherited Create(true);
  12.   FreeOnTerminate := true;
  13.   OnTerminate := AThreadDone; // prefix with @ if in Delphi mode
  14.   if not CreateSuspended then Start;
  15. end;

(Not exactly sure if the reintroduce; overload; are absolutely required.)

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #21 on: June 17, 2019, 02:58:46 pm »
Neat solution, any code can be improved upon at some time. The reintroduce is indeed not necessary. Maybe const ThreadDone, though
also related to equus asinus.

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: Error class 'external : SIGSEGV' when running Thread
« Reply #22 on: June 17, 2019, 03:02:34 pm »
So, back to old code then, without constructor.
In that case remember:
- CreateSuspended should be TRUE!
- First the setup, then call start
- Order is important.

By now this advice has been given not just by me, but by three "Old Hands" and we more or less agree.
« Last Edit: June 17, 2019, 03:05:13 pm by Thaddy »
also related to equus asinus.

ASerge

  • Hero Member
  • *****
  • Posts: 1423
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #23 on: June 17, 2019, 09:42:26 pm »
But you are correct, that could be en implementation detail which might not be exactly be implemented as I described so your approach will be indeed the safest course.
In Delphi documented that the thread starts in the AfterСonstructor. http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.Create, http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.AfterConstruction. I looked help in old versions of Delphi, there is the same. Unless in Delphi 1.0 it was not so.
It's also documented in FPC https://www.freepascal.org/docs-html/current/rtl/classes/tthread.afterconstruction.html
So it is safe to call inherited Create(false) inside the constructor.
By the way, the statement "if CreateSuspended = false then Start;" is not correct (should be removed " = false")

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #24 on: June 17, 2019, 11:11:18 pm »
So it is safe to call inherited Create(false) inside the constructor.
Good to know.

But if that's the case, the wiki is not correct.

It says...
Quote
AfterConstruction is overridden in TThread, it starts the thread if it was created in a suspended state.

Shouldn't it be "if it was created in a non suspended state" then?

In a suspended state the thread is only started after calling start.


incendio

  • Jr. Member
  • **
  • Posts: 92
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #25 on: June 18, 2019, 05:43:06 am »
A bit OOT, how to call procedure ThreadDone with parameter? Is it possible?

Previous code
Code: Pascal  [Select]
  1. TMainFrm = class(TForm)
  2.     btnStart: TButton;
  3.     procedure ThreadDone(Sender: TObject);
  4. end;
  5.  
  6. procedure TMainFrm.Go();
  7. var
  8.   Dt1 : TLocGetDtThr1;
  9. begin
  10.   Dt1 := TLocGetDtThr1.Create(True,@ThreadDone);  
  11. end;
  12.  

New Code
Code: Pascal  [Select]
  1. TMainFrm = class(TForm)
  2.     btnStart: TButton;
  3.     procedure ThreadDone(Sender: TObject; Thread:integer);
  4. end;

Look at the declaration of procedure ThreadDone, there is additional parameter. How to call it on variable Dt1?

Thaddy

  • Hero Member
  • *****
  • Posts: 9293
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #26 on: June 18, 2019, 09:00:35 am »
By the way, the statement "if CreateSuspended = false then Start;" is not correct (should be removed " = false")
??? Of course not. I set create suspended = true during setup and then test if the parameter assumes the thread should be started. But the remark of AfterConstruction I didn't know about.
The logic is the same, only in afterconstruction setup first, then call inherited afterconstruction. That also cannot overwrite things you need to setup.
also related to equus asinus.

PascalDragon

  • Hero Member
  • *****
  • Posts: 735
  • Compiler Developer
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #27 on: June 18, 2019, 09:18:24 am »
So it is safe to call inherited Create(false) inside the constructor.
Good to know.

But if that's the case, the wiki is not correct.
Then the wiki article needs to be fixed.

It says...
Quote
AfterConstruction is overridden in TThread, it starts the thread if it was created in a suspended state.

Shouldn't it be "if it was created in a non suspended state" then?

In a suspended state the thread is only started after calling start.
Please report a bug towards the documentation so that it isn't forgotten.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #28 on: June 18, 2019, 09:57:29 am »
A bit OOT, how to call procedure ThreadDone with parameter? Is it possible?
Not OT, and yes, it is possible. But not in the 'normal' way.

If you look at the TNotifyEvent as it is defined now you find:
Code: Pascal  [Select]
  1.   TNotifyEvent = procedure(Sender: TObject) of object;
So you see there is already one parameter you needed to provide.

When you want more/other parameters you need to define another procedure of your own.
Make sure it matches what you want exactly.

But the OnTerminate itself is private and can't be changed:
Code: Pascal  [Select]
  1. procedure TThread.CallOnTerminate;
  2. begin
  3.   FOnTerminate(Self);
  4. end;
So you can't any new parameters there.

You can create your own FMyTerminate methods.
Something like this. But note that there is a simpler way (see below).

Code: Pascal  [Select]
  1. type
  2.   TMyNotifyEvent = procedure(Sender: TObject; Thread:integer) of object;
  3.  
  4. type
  5.   TD3GetDtThr = class(TThread)
  6.   private
  7.     FMyTerminate: TMyNotifyEvent;
  8.     procedure CallMyTerminate;
  9.   protected
  10.     procedure Execute; override;
  11.     procedure DoTerminate; override; // we override DoTerminate to include calling our own MyTerminate
  12.   public
  13.     constructor Create(CreateSuspended: boolean; AThreadDone: TMyNotifyEvent); overload;
  14.     property MyTerminate: TMyNotifyEvent read FMyTerminate write FMyTerminate;
  15.   end;
  16.  
  17. constructor TD3GetDtThr.Create(CreateSuspended: boolean; AThreadDone: TMyNotifyEvent);
  18. begin
  19.   inherited Create(True);
  20.   FreeOnTerminate := True;
  21.   MyTerminate := AThreadDone; // prefix with @ if in Delphi mode
  22.   if not CreateSuspended then
  23.     Start;
  24. end;
  25.  
  26. procedure TD3GetDtThr.Execute;
  27. begin
  28.   //
  29. end;
  30.  
  31. procedure TD3GetDtThr.CallMyTerminate;
  32. begin
  33.   FMyTerminate(Self, 12345); // This is our own OnTerminate
  34. end;
  35.  
  36. procedure TD3GetDtThr.DoTerminate;
  37. begin
  38.   if Assigned(FMyTerminate) then
  39.     Synchronize(@CallMyTerminate);
  40.   inherited;
  41. end;

But as I said... it might be even simpler depending on your own code.

The TNotifyEvent has a Sender. The Sender of OnTerminate is always the TThread itself.
As can be seen from the source earlier.
Code: Pascal  [Select]
  1. FOnTerminate(Self); // the OnTerminate in the Thread passes itself to your OnTerminate procedure !!

So in your own ThreadDone you can access the Thread. Just make sure any variable you need are public.

Code: Pascal  [Select]
  1. procedure TMainFrm.ThreadDone(Sender: TObject);
  2. begin
  3.   if Sender is TD3GetDtThr then
  4.   begin
  5.     // here you can access TD3GetDtThr(Sender).Public_Variables
  6.   end;
  7. end;

Much simpler, isn't it  8-)
(Maybe I didn't need to explain the whole other method... but hey, we are here to learn  :P )

Please report a bug towards the documentation so that it isn't forgotten.
Done
« Last Edit: June 18, 2019, 10:28:38 am by rvk »

incendio

  • Jr. Member
  • **
  • Posts: 92
Re: [SOLVED] Error class 'external : SIGSEGV' when running Thread
« Reply #29 on: June 18, 2019, 10:54:26 am »
@rvk

Thanks a lot, I learn a lot today  :)