Recent

Author Topic: custom thread reading file does not respond properly  (Read 8182 times)

apeoperaio

  • Full Member
  • ***
  • Posts: 165
custom thread reading file does not respond properly
« on: September 02, 2017, 12:41:51 pm »
Porting my application to windows/linux to osx I encounter an issue with one of my thread.
One of my thread basically reads a file looking for strings.
It works properly on win and linux while on osx it does not allow me to interact with my application.
Here a sample code reproducing the issue. The thread basically reads the file till the end then starts again (just to replicate the behaviour occurring on big files).
On win and linux I can edit the tedit while the thread is running as well as resizing the form and basically interact with my application. On my macbook with SSD I can't (could be related to ssd?).
I am using laz 1.6.4 fpc 3.0.2.
In order to check the code below just replace
  AssignFile(F, 'yourtestfilename');
with a test file name.

Code: Pascal  [Select]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.   TShowStatusEvent = procedure(Status: String) of Object;
  12.  
  13.   TMyThread = class(TThread)
  14.   private
  15.     fStatusText : string;
  16.     FOnShowStatus: TShowStatusEvent;
  17.     procedure ShowStatus;
  18.   protected
  19.     procedure Execute; override;
  20.   public
  21.     Constructor Create(CreateSuspended : boolean);
  22.     property OnShowStatus: TShowStatusEvent read FOnShowStatus write FOnShowStatus;
  23.   end;
  24.  
  25.   { TForm1 }
  26.  
  27.   TForm1 = class(TForm)
  28.     Button1: TButton;
  29.     Edit1: TEdit;
  30.     Label1: TLabel;
  31.     procedure Button1Click(Sender: TObject);
  32.     procedure FormCreate(Sender: TObject);
  33.     procedure FormDestroy(Sender: TObject);
  34.   private
  35.     { private declarations }
  36.     MyThread: TMyThread;
  37.     procedure ShowStatus(Status: string);
  38.   public
  39.     { public declarations }
  40.   end;
  41.  
  42. var
  43.   Form1: TForm1;
  44.  
  45. implementation
  46.  
  47. {$R *.lfm}
  48.  
  49.  
  50. constructor TMyThread.Create(CreateSuspended : boolean);
  51. begin
  52.   FreeOnTerminate := True;
  53.   inherited Create(CreateSuspended);
  54. end;
  55.  
  56. procedure TMyThread.ShowStatus;
  57. // this method is executed by the mainthread and can therefore access all GUI elements.
  58. begin
  59.   if Assigned(FOnShowStatus) then
  60.   begin
  61.     FOnShowStatus(fStatusText);
  62.   end;
  63. end;
  64.  
  65. procedure TMyThread.Execute;
  66. var
  67.   newStatus : string;
  68.   F: Text;
  69. begin
  70.   fStatusText := 'TMyThread Starting...';
  71.   Synchronize(@Showstatus);
  72.   fStatusText := 'TMyThread Running...';
  73.   AssignFile(F, 'yourtestfilename');
  74.   reset(F);
  75.   while (not Terminated) do
  76.     begin
  77.       if eof(f) then
  78.         reset(f);
  79.       ReadLn(f, newStatus);
  80.       if NewStatus <> fStatusText then
  81.         begin
  82.           fStatusText := newStatus;
  83.           Synchronize(@Showstatus);
  84.         end;
  85.     end;
  86.   CloseFile(F);
  87. end;
  88.  
  89. { TForm1 }
  90.  
  91. procedure TForm1.Button1Click(Sender: TObject);
  92. begin
  93.   MyThread.Start;
  94. end;
  95.  
  96. procedure TForm1.FormCreate(Sender: TObject);
  97. begin
  98.   inherited;
  99.   MyThread := TMyThread.Create(true);
  100.   MyThread.OnShowStatus := @ShowStatus;
  101. end;
  102.  
  103. procedure TForm1.FormDestroy(Sender: TObject);
  104. begin
  105.   MyThread.Terminate;
  106.  
  107.   inherited;
  108. end;
  109.  
  110. procedure TForm1.ShowStatus(Status: string);
  111. begin
  112.   Label1.Caption := Status;
  113. end;
  114.  
  115. end.
  116.  

Thaddy

  • Hero Member
  • *****
  • Posts: 9436
Re: custom thread reading file does not respond properly
« Reply #1 on: September 02, 2017, 01:29:33 pm »
This part is wrong:
Code: Pascal  [Select]
  1. constructor TMyThread.Create(CreateSuspended : boolean);
  2. begin
  3.   FreeOnTerminate := True;
  4.   inherited Create(CreateSuspended);
  5. end;

Should be reversed. Your destructor is OK. (Because you set createsuspended to true)
« Last Edit: September 02, 2017, 01:49:28 pm by Thaddy »
also related to equus asinus.

apeoperaio

  • Full Member
  • ***
  • Posts: 165
Re: custom thread reading file does not respond properly
« Reply #2 on: September 02, 2017, 02:12:44 pm »
Ok, but I copied that code from:
http://wiki.freepascal.org/Multithreaded_Application_Tutorial#The_TThread_Class

Anyway, chenging it does not change the thread behaviour. My application does not respond after the thread starts.
Could be related to SSD drive?
Someone can test it on osx with or without ssd? And on win or linux with ssd drive?

Thaddy

  • Hero Member
  • *****
  • Posts: 9436
Re: custom thread reading file does not respond properly
« Reply #3 on: September 02, 2017, 02:25:48 pm »
Ok, but I copied that code from:
http://wiki.freepascal.org/Multithreaded_Application_Tutorial#The_TThread_Class
Another useless wiki entry.

Suppose the inherited create says in needs to have suspended or FreeOnTerminate to false? That is BASIC programmer error!! <very grumpy again  >:D> So you set true, inherited set it false? That's moronic... Who wrote that entry? shoot him (paintball, not waterpistol, needs to hurt a little)!

Anyway, if it didn't fix it, I will investigate further. O:-)

In Pascal classes(and C++  and the likes too) You FIRST call the inherited constructor and THEN call your own, because inherited can reset your intentions. (there are some highly technical hacks that never are supposed to happen, so ignore those). FF'ng bad programming.... >:D >:D >:( >:( >:( >:( 8-) O:-) (The 10 persons on this forum who can do it plz refrain from a response. Complicates the matter...for a border case... :P %))
« Last Edit: September 02, 2017, 02:59:53 pm by Thaddy »
also related to equus asinus.

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: custom thread reading file does not respond properly
« Reply #4 on: September 02, 2017, 04:48:01 pm »
This part is wrong:
Code: Pascal  [Select]
  1. constructor TMyThread.Create(CreateSuspended : boolean);
  2. begin
  3.   FreeOnTerminate := True;
  4.   inherited Create(CreateSuspended);
  5. end;

Should be reversed. Your destructor is OK. (Because you set createsuspended to true)

https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/examples/multithreading/mainunit.pas?view=markup&root=lazarus 

Thaddy

  • Hero Member
  • *****
  • Posts: 9436
Re: custom thread reading file does not respond properly
« Reply #5 on: September 02, 2017, 06:05:41 pm »
Indeed, the example is also wrong. It works by accident and violates OOP design.

Reason: TThread is a blackbox. You can not expect this violation of OOP rules (the use of a field or property in a derived class before the base class is initialized because that base class my initialze it already in the inherited constructor) to be true. Ever.
There's also no reason for it other than a kludge to make it work around bad design. That's a fact, not opinion.
Code: Pascal  [Select]
  1. constructor TMyThread.Create(CreateSuspended : boolean );
  2. begin
  3.   FreeOnTerminate := True; // says who?
  4.   inherited Create(CreateSuspended);// a proper implementation would now possibly reset FreeOnTerminate to false.......Clear?.
  5. end;
« Last Edit: September 02, 2017, 06:18:04 pm by Thaddy »
also related to equus asinus.

apeoperaio

  • Full Member
  • ***
  • Posts: 165
Re: custom thread reading file does not respond properly
« Reply #6 on: September 02, 2017, 06:17:50 pm »
Actually in my application I do it wright, I just copy and paste a simple example to reproduce my problem.

Anyway, any hint about the topic issue?

Thaddy

  • Hero Member
  • *****
  • Posts: 9436
Re: custom thread reading file does not respond properly
« Reply #7 on: September 02, 2017, 06:21:39 pm »
Yes. I (or someone else with sufficient knowledge - careful!) have to rewrite the example and the wiki since that works by accident. So first things first.
I get back to your original problem tomorrow.
also related to equus asinus.

sam707

  • Guest
Re: custom thread reading file does not respond properly
« Reply #8 on: September 03, 2017, 12:03:09 am »
Contrary to New or Getmem, class constructors initialize class record to zero...
when instanciating a class, the memory allocator sets the whole mem block to zero. IF the ancestor(s) do not manage one or more particular values in the class record, it will be inherited to zero. As it is not managed in the ancestor, it doesn't then matter if you manage it before or after the call to the ancestor constructor.

Don't forget your xanax, chess mater LOL  >:D
« Last Edit: September 03, 2017, 12:15:56 am by sam707 »

apeoperaio

  • Full Member
  • ***
  • Posts: 165
Re: custom thread reading file does not respond properly
« Reply #9 on: September 05, 2017, 11:02:11 am »
Anyone had the chance to check my issue?

Cyrax

  • Hero Member
  • *****
  • Posts: 773
Re: custom thread reading file does not respond properly
« Reply #10 on: September 05, 2017, 01:32:58 pm »
What happens if you change Synchronize to Queue?

apeoperaio

  • Full Member
  • ***
  • Posts: 165
Re: custom thread reading file does not respond properly
« Reply #11 on: September 05, 2017, 01:51:06 pm »
Modifying these lines:

Code: Pascal  [Select]
  1.           Queue(@ShowStatus);
  2.           //Synchronize(@Showstatus);

I got External SIGSEGV both on OSX and Windows.

apeoperaio

  • Full Member
  • ***
  • Posts: 165
Re: custom thread reading file does not respond properly
« Reply #12 on: September 05, 2017, 01:59:14 pm »
In order to further clarify my issue.
Apart from the sample code posted in this forum, my thread simply parse a file and o string matching. Very minimal operations, read the file do string match. And on OSX I cannot interact with my app when my thread is executing.

But if I add some additional operations to my thread loop I can interact with my application. My issue is that I don't really need to do more than I actually do with my thread.

Anyway, simply adding a Sleep(5) in my execute procedure I can see the thread working and I can interact with my app.
Obviously is not an option to a add a sleep in my thread, since it works as expected in win and linux.

Code: Pascal  [Select]
  1. procedure TMyThread.Execute;
  2. var
  3.   newStatus : string;
  4.   F: Text;
  5. begin
  6.   fStatusText := 'TMyThread Starting...';
  7.   Synchronize(@Showstatus);
  8.   fStatusText := 'TMyThread Running...';
  9.   AssignFile(F, 'yourtestfilename');
  10.   reset(F);
  11.   while (not Terminated) do
  12.     begin
  13.       if eof(f) then
  14.         reset(f);
  15.       ReadLn(f, newStatus);
  16.       if NewStatus <> fStatusText then
  17.       begin
  18.         fStatusText := newStatus;
  19.         //Queue(@ShowStatus);
  20.         Synchronize(@Showstatus);
  21.         Sleep(5);
  22.       end;
  23.     end;
  24.   CloseFile(F);
  25. end;        
  26.  


Cyrax

  • Hero Member
  • *****
  • Posts: 773
Re: custom thread reading file does not respond properly
« Reply #13 on: September 05, 2017, 02:06:32 pm »
You should definitely add some pause in your thread so it won't eat away CPU processing power and give some CPU time to other threads/processes to do some processing in their own.

apeoperaio

  • Full Member
  • ***
  • Posts: 165
Re: custom thread reading file does not respond properly
« Reply #14 on: September 05, 2017, 02:12:15 pm »
OK, but why?
Is it related to SSD drive? Or OSX?
If it is related to OSX I can add an IFDEF DARWIN, since I have no issues on win and linux.
If it is related ot SSD reading how could I check that my drive is SSD so I have to put a sleep or something?