Recent

Author Topic: Yet another Threads question..  (Read 628 times)

yo_mono

  • Newbie
  • Posts: 4
Yet another Threads question..
« on: December 27, 2019, 05:50:08 am »
Hi everyone.
Im sorry, i know there is a lot of post about threads.
But i really cant find my answer. Im sure the answer is there, if I can assemble the puzzle. But i cant, probably because im (sorta) new on this world. Im still learning and adding new concepts in my head.

I have this program with several buttons that runs a Tprocess, each one with differents Parameters. This tprocess is in a created Thread so my app doesn't freeze while is waiting for this process to finish (i read about Application.ProcessMessages, but i think this is a good oportunity to learn about Threads, so i decided to do it this way).

This is my code so far (this is a simplified version of the code, and im just showing the relevant parts of it):

Code: Pascal  [Select][+][-]
  1.  
  2. MyThread = class(Tthread)
  3.  
  4.   protected
  5.     procedure Execute; override;
  6.   end;
  7.  
  8. TForm1 = class(TForm)
  9.  
  10. procedure MyProcedure(ASender : TObject);
  11. procedure ButtonClick(ASender : TObject);
  12.  
  13. private
  14. public
  15. end;
  16.  
  17. var
  18.   MyProcess: TProcess;
  19.   L: TlistStrings;
  20.   Combo: TcomboBox;
  21.  
  22. implementation
  23.  
  24. uses
  25. {$R *.frm}
  26.  
  27. { TForm1 }
  28.  
  29.  
  30. procedure ButtonClick(ASender : TObject);
  31. var
  32.   Thread: MyThread;
  33. begin
  34.   thread := MyThread.Create(True);
  35.   thread.OnTerminate:= @MyProcedure;
  36.   thread.FreeOnTerminate:= True ;
  37.   thread.Start;
  38. end;
  39.  
  40.  
  41. procedure MyThread.Execute;
  42. begin
  43.   Try
  44.     MyProcess:= TProcess.Create(nil);
  45.     MyProcess.Executable := 'program.exe';
  46.     MyProcess.Parameters.Add('parameter1');
  47.     MyProcess.Options := MyThread.Options + [powaitonexit, ponoconsole, pousepipes];
  48.     MyProcess.Execute;
  49.     L := TStringList.Create;
  50.     L.LoadFromStream(MyProcess.Output);  
  51.   finally
  52.    MyProcess.Free;
  53.   end;
  54. end;
  55.  
  56.  
  57. procedure MyProcedure(ASender : TObject);
  58. begin
  59.   try
  60.     Combo.items.AddStrings(L);
  61.   finally
  62.     L.Free
  63.   end;
  64. end;
  65.  
  66.  

As you can see, is very simple:
You click "Button", it start the Thread, and set it to go to "MyPocedure" on terminate.
The thread starts, do what it has to do, and stores the result on a ListString.
Then, the last procedure, takes that ListString and use it to fill a combobox.
Easy peasy.


As i said, im not have just one button, but several. And all of them needs to use the same process, but with different parameters. And, some also would need to use another procedure after the Thread.
What i want to know is if i can REUSE the same Thread, more specifically the same MyThread.Execute procedure, but changing the Parameters, so i can save a lot of code writing.

My questions are: What is the correct way to do it? Should i create a unique Thread for all of them? It is (technically speaking) correct to reuse the Same Thread? How can i pass different parameters to the same "MyProcess"?

I know is a basic question (actually, right know im thinking a few ways to do it), but since im founding the bases of my learning right now, i want you to tell me the CORRECT way to do this.

I hope you can help me. Thank you in advance

PascalDragon

  • Hero Member
  • *****
  • Posts: 2264
  • Compiler Developer
Re: Yet another Threads question..
« Reply #1 on: December 27, 2019, 09:23:17 am »
You can pass the different arguments in the constructor of the thread, you just need to declare your own one:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyThread = class(TThread)
  3.   private
  4.     fArgs: String;
  5.   protected
  6.     procedure Execute; override;
  7.   public
  8.     constructor Create(const aArgs: String);
  9.   end;
  10.  
  11. constructor TMyThread.Create(const aArgs: String);
  12. begin
  13.   // call the original constructor
  14.   inherited Create(True);
  15.   // store arguments
  16.   fArgs := aArgs;
  17. end;
  18.  
  19. procedure TMyThread.Execute;
  20. begin
  21.   // ...
  22.   MyProcess.Parameters.Text := fArgs;
  23.   // ...
  24. end;

Of course you change determine yourself how arguments are passed: simple string, string array, TStringList. This is merely an example. :)

yo_mono

  • Newbie
  • Posts: 4
Re: Yet another Threads question..
« Reply #2 on: December 27, 2019, 04:02:09 pm »
Great! Time to read about Constuctors then..
Thanks

mr-highball

  • Full Member
  • ***
  • Posts: 211
    • Highball Github
Re: Yet another Threads question..
« Reply #3 on: December 27, 2019, 04:12:52 pm »
If you're working with threads, you may find it easier to use ezthreads. It simplifies a lot of the setup stuff and gives a simple interface to work with. Here's me shamelessly copying and pasting from a previous post I made,

ezthreads has that mechanism, here's a previous forum post with an example,
https://forum.lazarus.freepascal.org/index.php?action=post;topic=45818.msg329268;quote=329268

A sample from the github repo showing usage,
https://github.com/mr-highball/ezthreads/blob/master/test/ezthreads_tester.lpr#L181
Code: Pascal  [Select][+][-]
  1. (*
  2.   shows that await can be used for blocking for a single thread
  3. *)
  4. procedure TestSingleAwait;
  5. var
  6.   LThread:IEZThread;
  7.  
  8.   procedure Setup(Const AThread:IEZThread);
  9.   begin
  10.     Sleep(1000);
  11.     WriteLn('TestSingleAwait::setup finished');
  12.   end;
  13.  
  14. begin
  15.   LThread:=TEZThreadImpl.Create;
  16.   LThread
  17.     .Setup(Setup)
  18.     .Start;
  19.  
  20.   //call await with the thread to block until this thread has finished running
  21.   Await(LThread);
  22.   WriteLn('TestSingleAwait::done awaiting');
  23. end;
  24.  

It allows for
1. awaiting single thread - Await(Thread)
2. awaiting a group of threads - Await(GroupID)
3. awaiting all threads - Await
repo: https://github.com/mr-highball/ezthreads

There's a lot more examples showing usage in the tester app that comes with the library, but I'd be glad to answer any questions you had or show you how to setup a scenario you're trying to achieve,

Cheers 🍻
« Last Edit: December 27, 2019, 04:15:01 pm by mr-highball »

ASerge

  • Hero Member
  • *****
  • Posts: 1682
Re: Yet another Threads question..
« Reply #4 on: December 28, 2019, 02:06:32 am »
Code: Pascal  [Select][+][-]
  1. procedure MyThread.Execute;
  2. begin
  3.   Try
  4.     MyProcess:= TProcess.Create(nil);
  5.     MyProcess.Executable := 'program.exe';
  6.     MyProcess.Parameters.Add('parameter1');
  7.     MyProcess.Options := MyThread.Options + [powaitonexit, ponoconsole, pousepipes];
  8.     MyProcess.Execute;
  9.     L := TStringList.Create;
  10.     L.LoadFromStream(MyProcess.Output);  
  11.   finally
  12.    MyProcess.Free;
  13.   end;
  14. end;
By the way, try must be after TProcess.Create.

yo_mono

  • Newbie
  • Posts: 4
Re: Yet another Threads question..
« Reply #5 on: December 28, 2019, 05:36:12 am »
If you're working with threads, you may find it easier to use ezthreads. It simplifies a lot of the setup stuff and gives a simple interface to work with. Here's me shamelessly copying and pasting from a previous post I made.....

i definitely will take a look!  Thanks!


By the way, try must be after TProcess.Create.

ups  :-[ thanks! writed down in my mind!


 

TinyPortal © 2005-2018