Recent

Author Topic: tthread code tthread.create/tthread,execute/constructor  (Read 2026 times)

ASerge

  • Hero Member
  • *****
  • Posts: 1422
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #15 on: July 19, 2019, 10:44:48 pm »
Hi Toby, lover of lowercase characters and hater of punctuation marks ;D
The first note is about the number of threads. Better to quote a phrase from the Microsoft documentation, I think it is still relevant for *nix:
Quote
...you can create more threads. However, your application will have better performance if you create one thread per processor and build queues of requests for which the application maintains the context information. A thread would process all requests in a queue before processing requests in the next queue
Second. The thread object is created immediately in the constructor (the "Handle" property is available), so calling Sleep(1000) after creation looks strange.
Third. The thread control cannot be done directly. This is a parallel execution thread that runs independently of the main. For interaction use OS kernel objects: events, semaphores, etc. Or even a simple interlocked variable. Example:
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3. {$LONGSTRINGS ON}
  4.  
  5. uses SysUtils, Classes;
  6.  
  7. type
  8.   TTestThread = class(TThread)
  9.   strict private
  10.     FName: string;
  11.     FPauseRequest: LongInt;
  12.     FPausedEvent, FContinueEvent: PRTLEvent;
  13.     procedure ShowEvent(const Event: string);
  14.   protected
  15.     procedure Execute; override;
  16.   public
  17.     constructor Create(const AName: string);
  18.     destructor Destroy; override;
  19.     procedure PauseAndWait;
  20.     procedure Continue;
  21.   end;
  22.  
  23. constructor TTestThread.Create(const AName: string);
  24. begin
  25.   inherited Create(False);
  26.   FName := AName;
  27.   FPauseRequest := 0;
  28.   FContinueEvent := RTLEventCreate;
  29.   FPausedEvent := RTLEventCreate;
  30.   FreeOnTerminate := True;
  31. end;
  32.  
  33. procedure TTestThread.Continue;
  34. begin
  35.   ShowEvent(#9'continue request');
  36.   while InterLockedDecrement(FPauseRequest) <> 0 do
  37.     { No body };
  38.   RTLeventSetEvent(FContinueEvent);
  39. end;
  40.  
  41. destructor TTestThread.Destroy;
  42. begin
  43.   ShowEvent('destroyed');
  44.   RTLeventdestroy(FContinueEvent);
  45.   RTLeventdestroy(FPausedEvent);
  46.   inherited Destroy;
  47. end;
  48.  
  49. procedure TTestThread.Execute;
  50. begin
  51.   while not Terminated do
  52.   begin
  53.     if FPauseRequest <> 0 then
  54.     begin
  55.       ShowEvent(#9'paused');
  56.       RTLeventSetEvent(FPausedEvent);
  57.       RTLeventWaitFor(FContinueEvent);
  58.       ShowEvent(#9'resumed');
  59.     end;
  60.     ShowEvent('working');
  61.     Sleep(500 + Random(500));
  62.   end;
  63. end;
  64.  
  65. procedure TTestThread.PauseAndWait;
  66. begin
  67.   ShowEvent(#9'pause request');
  68.   InterLockedIncrement(FPauseRequest);
  69.   RTLeventWaitFor(FPausedEvent);
  70. end;
  71.  
  72. procedure TTestThread.ShowEvent(const Event: string);
  73. begin
  74.   Writeln('[', FormatDateTime('nn:ss.zzz', Time), '] thread ', FName, ' ', Event);
  75. end;
  76.  
  77. var
  78.   Threads: array[0..3] of TTestThread;
  79.   i: Integer;
  80. begin
  81.   for i := Low(Threads) to High(Threads) do
  82.     Threads[i] := TTestThread.Create(i.ToString);
  83.   TThread.Sleep(3000); // To see all threads work
  84.   Threads[2].PauseAndWait;
  85.   TThread.Sleep(1000); // Do some with Threads[2]
  86.   Threads[2].Continue;
  87.   TThread.Sleep(3000); // To see all threads work
  88.   for i := Low(Threads) to High(Threads) do
  89.     Threads[i].Terminate;
  90.   Writeln('Press Enter');
  91.   Readln;
  92. end.

Peter H

  • Jr. Member
  • **
  • Posts: 57
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #16 on: July 20, 2019, 10:31:21 am »


another case of no good examples or code examples on the internet :

i see in a number of places that it isn't recommended to use external threads with fpc like in this (badly formulated function example)

function ethread(i: cint): clong; cdecl; external 'pthread';

so can be able to use the c thread functions like pthread_create( pthread_join(  etc

i've used other c extern coding and wonder why this particular usage is frowned on?




I do not know, if you have read this:
https://wiki.freepascal.org/Multithreaded_Application_Tutorial

There is a short explanation for the above problem given:
Some pascal related data structures must be initialized before a thread is run. And probably these structures must be kept up to date, when the thread is manipulated.

This is, why external threads cannot be used without special precautions.
It is possible to create a nonsuspended thread, if a custom constructor is used.

This is how I understand it.
I am not an expert of FPC but have used several industrial realtime environments on DOS and embedded many years ago.

(Still today I dream of (DR)DOS where you have complete control over the whole machine, but I dont use it anymore.)
« Last Edit: July 20, 2019, 11:44:42 am by Peter H »

Thaddy

  • Hero Member
  • *****
  • Posts: 9284
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #17 on: July 20, 2019, 10:46:01 am »
Good, old but still valid TThread examples are here http://nickhodges.com/MultiThreadingInDelphi/ToC.html. Also works on FPC. Some is windows centric.
Note that TThread has now - 2019 - way more features than back then - 2001 -, for example all class functions

There are examples for some of those those in the manuals, e.g. https://www.freepascal.org/docs-html/rtl/classes/tthread.executeinthread.html has multiple examples.
« Last Edit: July 20, 2019, 10:49:47 am by Thaddy »
also related to equus asinus.

PascalDragon

  • Hero Member
  • *****
  • Posts: 712
  • Compiler Developer
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #18 on: July 20, 2019, 10:50:02 am »
Very basically, sleep(X) tells the system to suspend the process for at least the next X milliseconds. When X is 0 it means the process just relinquishes the rest of its currently alloted time-slice.
You mean thread, not process. In this case it's an important difference. ;)

lucamar

  • Hero Member
  • *****
  • Posts: 2137
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #19 on: July 20, 2019, 11:29:53 am »
Ah .. yes, thread, not process. :-[

Those terms are prone to mental-glitches and slips of the tongue---even man pages have them wrong sometimes!
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 635
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #20 on: July 20, 2019, 11:35:41 pm »
Hi Toby, lover of lowercase characters and hater of punctuation marks ;D
The first note is about the number of threads. Better to quote a phrase from the Microsoft documentation, I think it is still relevant for *nix:
Quote
...you can create more threads. However, your application will have better performance if you create one thread per processor and build queues of requests for which the application maintains the context information. A thread would process all requests in a queue before processing requests in the next queue

Microsoft instantiates thousands of threads when Windows starts...

Their description changes all the time. They did build a comprehensive parallel framework for .NET, but the implementation is still last century. It is clear that they use the hard but good way themselves, but try to automate it in their development tools, because it is teh hard for your average programmer.

Peter H

  • Jr. Member
  • **
  • Posts: 57
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #21 on: July 21, 2019, 12:14:47 am »
There are two situations to differentiate:

1) There are many slow (blocking IO) waiting intensive processes with a lot of sleeping that can be decoupled by delegating them to threads.
In this case the main program can become faster when it uses many threads, even if all threads run on only one core..

2) There are computing intensive tasks that can be parallelized by delegating them to threads and execute these tasks in parallel..

In this case the whole program can become faster as long as each thread can be assigned to a different core.

There is a caveat: Modern CPUs use dynamic clock rates. If more than one or two core runs they throttle the clock rate to avoid too much heat ;-)
« Last Edit: July 21, 2019, 12:19:02 am by Peter H »

Thaddy

  • Hero Member
  • *****
  • Posts: 9284
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #22 on: July 21, 2019, 09:59:44 am »
There is a caveat: Modern CPUs use dynamic clock rates. If more than one or two core runs they throttle the clock rate to avoid too much heat ;-)
Yes, I ran into that with the Raspberry Pi 4: if you max out the cores it throttles down if the temp is higher than 80c. A heat sink set solved that. Even a passive one.
also related to equus asinus.

PascalDragon

  • Hero Member
  • *****
  • Posts: 712
  • Compiler Developer
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #23 on: July 21, 2019, 10:03:21 am »
Microsoft instantiates thousands of threads when Windows starts...
But that doesn't mean that they're all running all the time - otherwise the Task Manager would show more activity. Most threads are just waiting for a handle (from an event, from a file, another thread, another process, etc.) to be triggered before they do some work and then wait again.

lucamar

  • Hero Member
  • *****
  • Posts: 2137
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #24 on: July 21, 2019, 10:43:38 am »
A heat sink set solved that. Even a passive one.

Just poped into my head the image of a huge server farm and an intern strugling with a huge bag full of heat sinks.  :D ;D

Thanks, Thaddy; needed a laugh just about now. :)

(Not laughing at you, of course: I've done the same hundreds of times: summers here can be death to computers.)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

Peter H

  • Jr. Member
  • **
  • Posts: 57
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #25 on: July 21, 2019, 10:45:45 am »
I have the AMD Phenom, six cores.
If only one core is running, it can run faster.

There are even different power management policies that can be adjusted in BIOS.
The clock rates are adjusted dynamically.
I did not look into this for years, because the computer is fast enough for my purposes usually and as long a system works, I dont change it. ;-)

This said there are other undividable or limited ressources like FPU, GPU, memory bandwith, cache size, heap management and as soon as the threads compete for them, the gain of parallel computing becomes lower than expected.

mr-highball

  • Jr. Member
  • **
  • Posts: 69
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #26 on: July 21, 2019, 03:56:43 pm »
You may find use in ezthreads, either by using it as an alternative to standard tthread, or by seeing how I implemented some of the features (uses tthread under the hood)

Here's a link to several examples/use cases,
https://github.com/mr-highball/ezthreads/blob/master/test/ezthreads_tester.lpr

And here's previous post of mine,
 
A simple to use reference counted solution that you may want to look at OP is ezthreads. It lets you define the thread's behavior and settings (timeout, etc..)  in a fluent way, and comes with Await functionality similar to c#

I've written some previous posts here:
https://forum.lazarus.freepascal.org/index.php/topic,44274.msg311176.html#msg311176
-Highball

toby

  • Jr. Member
  • **
  • Posts: 66
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #27 on: August 05, 2019, 12:15:02 am »
Hi mr-highball

the ezthreads compiles on my machine good and looks very interesting but the number of hints generated with -vh almost emptied a full box of paper by my line printer

sample

fgl.pp(1792,1) Hint: "inherited" not yet supported inside inline procedure/function

fgl.pp(1803,8) Note: Call to subroutine "function TFPGMapObject<System.AnsiString,ezthreads.collection.TFPGInterfacedObjectList<ezthreads.IEZThread>>.IndexOf(const AKey:AnsiString):LongInt;" marked as inline is not inlined

my fpc is 3.1.1 - which are you using?  do you have any information about these - they are interesting to google

also the link you give here is not good this is the correct topic i didn't do it to your exact post though

https://forum.lazarus.freepascal.org/index.php/topic,44274.0.html

these are the reworked links from the above link - the topics these links should point to
https://forum.lazarus.freepascal.org/index.php/topic,45441.15.html
https://forum.lazarus.freepascal.org/index.php/topic,43353.0.html
https://forum.lazarus.freepascal.org/index.php/topic,42421.0.html

You may find use in ezthreads, either by using it as an alternative to standard tthread, or by seeing how I implemented some of the features (uses tthread under the hood)

Here's a link to several examples/use cases,
https://github.com/mr-highball/ezthreads/blob/master/test/ezthreads_tester.lpr

And here's previous post of mine,
 
A simple to use reference counted solution that you may want to look at OP is ezthreads. It lets you define the thread's behavior and settings (timeout, etc..)  in a fluent way, and comes with Await functionality similar to c#

I've written some previous posts here:
https://forum.lazarus.freepascal.org/index.php/topic,44274.msg311176.html#msg311176

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7605
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #28 on: August 05, 2019, 12:43:15 am »
There is a caveat: Modern CPUs use dynamic clock rates. If more than one or two core runs they throttle the clock rate to avoid too much heat ;-)

Yeah, but only like maximally 10% or so(200,300MHz for usually 3-4 GHz processors) , while 6 times the cores is then still 6*90%=540% of the single core speed.

mr-highball

  • Jr. Member
  • **
  • Posts: 69
Re: tthread code tthread.create/tthread,execute/constructor
« Reply #29 on: August 05, 2019, 12:49:00 am »
Hey Toby, thanks for checking my library out. As for the the hints you listed, those are showing as hints for the fgl unit (which ezthreads uses and is a system unit) not actually from any of the ezthreads code.

To your other question, I generally compile for stable fpc (3.0.4) but I recently did some work to try to adapt things to work a bit more "functional" which required latest trunk (due to the use of generic global methods) -> https://forum.lazarus.freepascal.org/index.php/topic,45818.msg329476.html#msg329476
The standard threading code will work fine (ezthreads, ezthreads.collections) in stable and your version, just the new stuff I was working on needs trunk.
-Highball