Recent

Author Topic: Passing an array to a TThread function  (Read 5736 times)

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Passing an array to a TThread function
« on: October 20, 2016, 01:17:31 am »
Hi!
I am trying to pass an array to the constructor of the class that I would be using as thread in the unit below.
Copying the array with a for loop would decrease the execution time so I would not consider it as an option.
I am getting error: 'find.pas(77,14) Error: Incompatible types: got "{Open} Array Of DictionaryEntry" expected "FindName.{Dynamic} Array Of DictionaryEntry"'.

I am trying to follow up the 'http://wiki.freepascal.org/Example_of_multi-threaded_application:_array_of_threads' tutorial.
I have read the forum entry 'http://forum.lazarus.freepascal.org/index.php?topic=24853.0' but did not understand much.

Please advise how I could pass the array to the thread constructor.

Thank you

Code: Pascal  [Select][+][-]
  1. UNIT find;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. INTERFACE
  6.  
  7. USES
  8. Classes, SysUtils, structures, utils, strutils;
  9.  
  10. TYPE
  11. FindName = CLASS(TThread)
  12. private
  13.   _Name   : NameEntry;
  14.   _Dictio   : ARRAY OF DictionaryEntry;
  15.  
  16. protected
  17.   PROCEDURE Execute; override;
  18. public
  19.   PROPERTY Terminated;
  20.   CONSTRUCTOR Create(VAR AName : NameEntry;var Dictio : ARRAY OF DictionaryEntry);
  21. END;
  22.  
  23. IMPLEMENTATION
  24.  
  25. PROCEDURE FindName.Execute;
  26. VAR
  27.   i, j : INTEGER;
  28.   u : Util;
  29.   exname : TStringArray;
  30.   isfound : BOOLEAN;
  31.   buf_name : STRING;
  32.  
  33. BEGIN
  34.   u := Util.Create;
  35.   exname := u.ExplodeString(' ', _Name.FullName, 99);
  36.   u.Free;
  37.  
  38.   FOR i := 0 TO Length(exname) - 1 DO
  39.   BEGIN
  40.  
  41.     buf_name := trim(exname[i]);
  42.  
  43.     IF Length(trim(buf_name)) > 1 THEN
  44.     BEGIN
  45.  
  46.       j := 0;
  47.       isfound := False;
  48.  
  49.       FOR j := 0 TO Length(_Dictio) - 1 DO
  50.         IF AnsiContainsText(_Dictio[j].Name, exname[i]) THEN
  51.         BEGIN
  52.           isfound := True;
  53.           break;
  54.         END;
  55.  
  56.       IF not isfound THEN
  57.         _Name.Issue := _Name.Issue + '|Not Found: ' + exname[i];
  58.     END;
  59.  
  60.   END;
  61. END;
  62.  
  63.  
  64. CONSTRUCTOR FindName.Create(VAR AName : NameEntry;var Dictio : ARRAY OF DictionaryEntry);
  65. BEGIN
  66.   _Name := AName;
  67.   SetLength(_Dictio, Length(Dictio));
  68.   _Dictio := Dictio;
  69. END;
  70.  
  71. END.
  72.  

structures as below:

Code: Pascal  [Select][+][-]
  1. UNIT structures;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. INTERFACE
  6.  
  7. USES
  8. Classes, SysUtils;
  9.  
  10. TYPE
  11. NameEntry = RECORD
  12.   FullName: STRING;
  13.   Issue: STRING;
  14. END;
  15.  
  16. TYPE
  17. DictionaryEntry = RECORD
  18.   Name: STRING;
  19.   TypeOfEntry: INTEGER;
  20. END;
  21.  
  22. type
  23.   TStringArray = array of string;
  24.  
  25. IMPLEMENTATION
  26.  
  27. END.
  28.  
  29.  
« Last Edit: October 22, 2016, 12:28:52 am by tudi_x »
Lazarus 2.0.2 64b on Debian LXDE 10

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Passing an array to a TThread function
« Reply #1 on: October 20, 2016, 02:27:32 am »
Code: [Select]
_Dictio   : ARRAY OF DictionaryEntry;
is a dynamic array, whilst Dictio in the following declaration
Code: [Select]
CONSTRUCTOR Create(VAR AName : NameEntry;var Dictio : ARRAY OF DictionaryEntry);
is an open array

See also here with a (workable) example here (sorry i was unable to find a wiki entry or something related in online fpc manual.

So, you solve it by creating a new type for the array, which is then to be used everywhere when addressing, just like your TStringArray definition.

PS: afaik the setlength isn't necessary.
« Last Edit: October 20, 2016, 02:47:39 am by molly »

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: Passing an array to a TThread function
« Reply #2 on: October 20, 2016, 02:34:25 pm »
I created

Code: Pascal  [Select][+][-]
  1. TYPE
  2. Dictionary = ARRAY OF DictionaryEntry;  
  3.  

and it worked.
Thank you!
Lazarus 2.0.2 64b on Debian LXDE 10

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: [SOLVED] Passing an array to a TThread function
« Reply #3 on: October 22, 2016, 12:28:32 am »
I modified my code as per attached.
When debugging I get an invalid pointer operation at the line that refers to the thread local array variable:

Code: Pascal  [Select][+][-]
  1. CONSTRUCTOR FIND.Create(AName : STRING; ASentence : TJustWords);
  2. BEGIN
  3.   FreeOnTerminate := False;
  4.  
  5.   _name := AName;
  6.   SetLength(_sentence, Length(ASentence));
  7.   _sentence := ASentence;
  8.   _isfound := False;
  9.   _isready := False;
  10.  
  11.   INHERITED Create(False);
  12. END;
  13.  

Please advise what I am missing.
« Last Edit: October 22, 2016, 12:32:54 am by tudi_x »
Lazarus 2.0.2 64b on Debian LXDE 10

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Passing an array to a TThread function
« Reply #4 on: October 22, 2016, 01:05:17 am »
You're passing along a pointer of the array. e.g. your 'local' copy is actually pointing to the global array.

e.g. guess/check what _sentence := ASentence; actually does
« Last Edit: October 22, 2016, 01:11:59 am by molly »

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: Passing an array to a TThread function
« Reply #5 on: October 22, 2016, 01:11:01 am »
I am a beginner. I did not work with pointers yet.
I did not understand what I would need to modify.
Could you please detail more what I would need to modify?
Lazarus 2.0.2 64b on Debian LXDE 10

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Passing an array to a TThread function
« Reply #6 on: October 22, 2016, 01:12:22 am »
I am a beginner. I did not work with pointers yet.
Which is no excuse for not applying the basics  ;D

Quote
I did not understand what I would need to modify.
Could you please detail more what I would need to modify?

Let's start with something fundamental and change:
Code: Pascal  [Select][+][-]
  1.         IF vloop > Length(n) - 1 THEN
  2.           searches[j] := f.Create(n[i], s)   //do not use threads for this case
  3.         ELSE
  4.           searches[j] := f.Create(n[i + j], s);
  5.  
into
Code: Pascal  [Select][+][-]
  1.         IF vloop > Length(n) - 1 THEN
  2.           searches[j] := find.Create(n[i], s)   //do not use threads for this case
  3.         ELSE
  4.           searches[j] := find.Create(n[i + j], s);
  5.  

At least that lets the threads run  :)

Drats, now the main program will not stop running.

So, taking a closer look at:
Code: Pascal  [Select][+][-]
  1. PROCEDURE FIND.Execute;
  2. VAR
  3.   i : INTEGER;
  4.  
  5. BEGIN
  6.   FOR i := 0 TO Length(_sentence) - 1 DO
  7.     IF AnsiContainsText(_sentence[i], _name) THEN
  8.     BEGIN
  9.       _isfound := True;
  10.       exit;
  11.     END;
  12.  
  13.   _isready := True;
  14. END;
  15.  

Which makes the following check fail:
Code: Pascal  [Select][+][-]
  1.       {Wait for threads to finish}
  2.       WHILE no_threads_ready <> no_threads DO
  3.       BEGIN
  4.         no_threads_ready := 0;
  5.         j := 0;
  6.  
  7.         FOR j := 0 TO no_threads - 1 DO
  8.           IF searches[j].IsReady THEN
  9.             no_threads_ready := no_threads_ready + 1;
  10.  
  11.       END;
  12.  

Can you spot the why ?
« Last Edit: October 22, 2016, 04:57:02 am by molly »

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: Passing an array to a TThread function
« Reply #7 on: October 22, 2016, 03:35:33 pm »
I think because of the exit.
In case the Execute is run it will not reach _isready := True;.

I have commented the exit but searches[j].IsReady does not seem to become true.
What would be the cause?



Lazarus 2.0.2 64b on Debian LXDE 10

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: Passing an array to a TThread function
« Reply #8 on: October 22, 2016, 04:34:39 pm »
I switched from the debugger to writeln and it looks like the IsReady property is updated.
I think it works now. The updated version of the code is attached.

Thank you for the help.
Lazarus 2.0.2 64b on Debian LXDE 10

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Passing an array to a TThread function
« Reply #9 on: October 22, 2016, 10:20:54 pm »
I think because of the exit.
That is indeed correct.

If you have found the text you are searching for and then do an exit, the thread is actually finished (which is the usual way of detecting if your thread is... well... finished  :) )

So by not setting the _isready property value, the loop which checks if all your threads are 'done', never meets the conditions you are checking for.

Indeed if you remove the exit (or set the _isready value when you've found the text and then exit), things will begin to start working as intended.

Have fun !  :)

 

TinyPortal © 2005-2018