Lazarus

Programming => General => Topic started by: toby on July 17, 2019, 07:09:03 pm

Title: tthread code tthread.create/tthread,execute/constructor
Post by: toby on July 17, 2019, 07:09:03 pm
Hi

i'm exploring what is really going on with the threading code i have and would love to understand it

there really is no good explanation on the net for what i have here using tthread (any references would be welcomed)

i got the basic coding structure from the fpc sources -> /packages/fcl-base/examples/threads.pp

i have studied (studied := read many many times) especially the tthread class section and i can't get the understanding i'd like from it

-

my basic tthread program structure is

program ft2;

type tmthread = class(tthread)
       ch : longint;
       procedure execute; override;
       constructor create(c : longint);
       end;

var t : tmthread;

procedure wf(p : longint);
begin
..
sysutils.executeprocess(curl, ....
..
end;

procedure tmthread.execute;
begin
wf(ch);
end;

constructor tmthread.create(c : longint);
begin
ch := c;
inherited create(false);
end;


begin
for i := 1 to 750 do
  begin
  t := tmthread.create(i);
  end;

sleep(1000);

end.

-

my goal is to understand what happens when t := tmthread.create(i);   is called

why the tmthread,create doesn't need to be passed 'ch'
my understanding : tmthread.execute is in the tmthread class so it gets all of tmthread class variables?

why the need for separate tmthread.create and tmthread.execute 'objects'? (procedure tmthread.create and consturctire tmthread.create ?)
can they be combined into one constructor/procedure?
and what the inherited create(false) really means.

thank you

--
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Remy Lebeau on July 17, 2019, 08:28:52 pm
my goal is to understand what happens when t := tmthread.create(i);   is called

TThread is just a class like any other.  Create() is its constructor (just like with most other classes).  You have to create an object instance of the class in memory before you can use it.  No different than any other class.

why the tmthread,create doesn't need to be passed 'ch'
my understanding : tmthread.execute is in the tmthread class so it gets all of tmthread class variables?

Yes.  You pass a value to your class's constructor, which stores that value in a member variable, which is accessible to all methods of the class.  No different than how any other class works.

why the need for separate tmthread.create and tmthread.execute 'objects'? (procedure tmthread.create and consturctire tmthread.create ?)

They are not 'objects'.  Create() is a constructor, Execute() is a procedure method.

Where TThread differs from other classes is that its Execute() method is always called in the context of a dedicated worker thread that is different than the thread that calls the constructor.

You do know what is a thread (https://en.wikipedia.org/wiki/Thread_(computing)) is, don't you?  If not, you need to go study up on that.  Any decent programing book should cover that topic.

can they be combined into one constructor/procedure?

No.  Create() creates the class object in memory, and then creates a worker thread that calls Execute() on that object.

and what the inherited create(false) really means.

The base TThread constructor (https://www.freepascal.org/docs-html/rtl/classes/tthread.create.html) has a boolean parameter named CreateSuspended:

Code: [Select]
public constructor TThread.Create(
  CreateSuspended: Boolean;
  const StackSize: SizeUInt = DefaultStackSize
);

Your derived class's constructor is calling the base class's constructor, telling it to create its worker thread in a non-suspended state, ie the thread starts running as soon as it is created (well, after the constructor exits, anyway).

Sometimes, you may need to set CreateSuspended to True instead, to delay the thread from running until you explicitly call TThread.Resume() (https://www.freepascal.org/docs-html/rtl/classes/tthread.resume.html) or TThread.Start() (https://www.freepascal.org/docs-html/rtl/classes/tthread.start.html).  Typically, you do this when you need to perform additional initializations after the constructor exits on things that the thread needs to access.  Or, if you want to create a pool of reusable threads that are resumed and suspended on-demand.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Peter H on July 17, 2019, 09:19:01 pm
I dont know, if this program will run. I doubt it.

It creates 750 threads in the adress-space of your process.
The default stacksize for threads -in windows- is 4 megabytes.
So this program would need 3 gigabytes of adress-space, all in your process.
This might be possible in a 64 bit process, but probably not in 32  bit.

Note: It will need this adress-space, but not the physical memory.
The memory needed ist only the memory that is actually touched (used). (If you have an OS with paged memory)

Better start with something simpler, e.g. "multithreadingexample1" from the examples in lazarus.
You can then set a breakpoint at create(), start the program and then browse the sourcecode in lazarus.
(It is a little bit difficult, because a lot of sourcecode sits in include files)

All the best.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on July 17, 2019, 11:21:16 pm
Remy Lebeau

thank you - just what i was needing

are t.terminate; and t.destroy not needed in my case since the threads end on their own in wf() which ends after loop is done?

at the end to keep program alive until all threads are finish - what do you use?

is something like this used and if so should i increase or remove the sleep?

repeat
  sleep(10);  <- 
until t.finished;

---

Peter H

yes indeed it runs - 750 is close to the maximum number of threads that can be created on my computer (767-780 are the max that can created) and .... yes i have 3GB of ram on my machine

in the example multithreainexample1 (which compiles and runs on my machine btw)

the /usr/local/lazarus/examples/multithreading/mainunit.pas
has constructor Create(CreateSuspended: boolean);   

mine is   constructor tmthread.create(c : longint);   how come i don't have any problem passing the parameter c which is the loop/thread number?


Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: lucamar on July 18, 2019, 01:45:08 am
in the example multithreainexample1 (which compiles and runs on my machine btw)

the /usr/local/lazarus/examples/multithreading/mainunit.pas
has constructor Create(CreateSuspended: boolean);   

mine is   constructor tmthread.create(c : longint);   how come i don't have any problem passing the parameter c which is the loop/thread number?

You're creating a new different constructor. Aren't you getting any warnings/errors about your constructor hiding the inherited or about lacking "overload"? (Depends on the $mode directive, if any)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on July 18, 2019, 02:24:18 am
Hi lucamar

so constructor line is like a procedure line - i thought it was a static thing

my compile directives are    -S2ghc   (gotta make sure my gotos work) in /etc/fpc.cfg

no warning/errors and i have -vh on fpc command line also for this project (and testing out -XX for first time on this project on the fpc command line too)

(-XX knocks the size of my lazarus projects in half)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: lucamar on July 18, 2019, 08:13:25 am
so constructor line is like a procedure line - i thought it was a static thing

It is basicaly a normal method with the special characteristic that when called as a class method, ie. when doing:
Code: Pascal  [Select]
  1. AnObject := TClass.Create(whatever);
it does some magic behind scenes to create the object instance: allocates memory, builds the VMT if needed, etc. If called as a normal mehod it just executes the code (or fails if the instance doesn't exists) as a normal method would.

Since your code works, it's obvious that the "overload" keyword is not needed. I don't remember for sure but it may be because you're using objfpc mode (-S2, equivalent to -Mobjfpc). It's probably somewhere in the manuals.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: PascalDragon on July 18, 2019, 09:22:34 am
are t.terminate; and t.destroy not needed in my case since the threads end on their own in wf() which ends after loop is done?

at the end to keep program alive until all threads are finish - what do you use?

Don't call Destroy directly, use Free instead as the later will correctly handle the case if the instance variable is Nil.

You need to use Terminate if you want to stop a thread from the outside though your thread's Execute method needs to check for Terminated and abort cooperatively.

The way you wrote it you need to free all thread instances you created so you need to store them in an array or list so that you can call Free on them once they are Finished. You can also use TThread.WaitFor to wait on each until its done with its execution.

Alternatively you can set FreeOnTerminate to True (e.g. inside your constructor before you call the inherited one). In that case however you must not touch the thread instance from outside as it could have been freed already leading to an access violation (yes, there are specific cases where this works, but let's keep to the general case). Thus you need to use some alternate way to tell the main program that all threads finished.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on July 18, 2019, 03:40:32 pm
PascalDragon

this works - if i have a real delay finishing the wf thread then the threads get totally unique threadid but if there is no delay in it finishing then the code seems to reuse threadid in alternate threads (the system tries to conserve resources?)

constructor tmthread.create(c : longint);
begin
ch := c;
inherited create(false);
freeonterminate := true;     <---- added
end;

aren't all threads freed automatically when the main program ends?

---

to keep program alive until all threads are finish - what do you use?

i'm using something like this used and if so should i increase or remove the sleep?

repeat
  sleep(10);  <-
until t.finished;

---

lucamar

https://www.freepascal.org/docs-html/ref/refsu79.html

https://wiki.freepascal.org/Compiler-generated_data_and_data_structures

probably best for me to just appreciate what goes on behind the scenes and be glad it works
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: lucamar on July 18, 2019, 04:27:34 pm
Quote
probably best for me to just appreciate what goes on behind the scenes and be glad it works
Yeah, I'm like that too: Take some quite time to read the docs and get at least a general view, be glad it works ... and then thank the gods I'm not the one that has to make it work! :D
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on July 18, 2019, 04:53:28 pm

am i creating potential problem by not using private, protectd, public here?
i don't create units usually so don't know if they are really needed here or not

type tmthread = class(tthread)
//   private
       ch : longint;
//   protected
       procedure execute; override;
//   public
       constructor create(c : longint);
       end;

---

Quote
probably best for me to just appreciate what goes on behind the scenes and be glad it works
Yeah, I'm like that too: Take some quite time to read the docs and get at least a general view, be glad it works ... and then thank the gods I'm not the one that has to make it work! :D

well the good thing is that almost all the behind the scenes magic code is written in fpc so it looks familiar (and not scary)
but i do see something called assembler every once in a while though - <shudder>

-

did you get your apollo guidance computer ?
can you believe they are still trying to get people to believe they sent a rocket device to that thing that moves in the sky and landed on it

http://www.ibiblio.org/apollo/download.html

---
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Remy Lebeau on July 19, 2019, 12:27:10 am
The default stacksize for threads -in windows- is 4 megabytes.

Actually, it is dependent on compiler settings, not the OS.  The PE header of an executable specifies the stack size.  That value gets set to whatever you configure your compiler to generate.  But an application's code can override that size at runtime by calling the Win32 CreateThread() or the RTL's BeginThread() directly.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: PascalDragon on July 19, 2019, 09:25:29 am
this works - if i have a real delay finishing the wf thread then the threads get totally unique threadid but if there is no delay in it finishing then the code seems to reuse threadid in alternate threads (the system tries to conserve resources?)
It totally depends on the operating system whether it reuses thread IDs, but it is definitely free to do so, so you shouldn't rely on the thread ID if you create many short lived threads.

aren't all threads freed automatically when the main program ends?
It depends on the operating system whether the program ends when the main thread returns or only ends if all threads terminated. Also in your example it might not matter, but in more complex cases you might want the threads to finish gracefully (maybe one is currently writing in a file / to a database?).


am i creating potential problem by not using private, protectd, public here?
i don't create units usually so don't know if they are really needed here or not

type tmthread = class(tthread)
//   private
       ch : longint;
//   protected
       procedure execute; override;
//   public
       constructor create(c : longint);
       end;

It's not a problem, but it's cleaner to correctly encapsulate fields, methods, etc.

The default stacksize for threads -in windows- is 4 megabytes.

Actually, it is dependent on compiler settings, not the OS.  The PE header of an executable specifies the stack size.  That value gets set to whatever you configure your compiler to generate.  But an application's code can override that size at runtime by calling the Win32 CreateThread() or the RTL's BeginThread() directly.
It is also OS dependant. For example on Unix the information is not retrieved from the executable, but the environment. See the man page for pthread_create (http://man7.org/linux/man-pages/man3/pthread_create.3.html) (Notes section).
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on July 19, 2019, 03:57:49 pm

aren't all threads freed automatically when the main program ends?
It depends on the operating system whether the program ends when the main thread returns or only ends if all threads terminated. Also in your example it might not matter, but in more complex cases you might want the threads to finish gracefully (maybe one is currently writing in a file / to a database?).

my system is on linux

i had to use something to keep thØe main thread open until all the threads finished

i started with a readln; then used  a sleep(2000); and then found property t.finished to keep the main program open until the threads finished with

repeat
writeln('1 t.finished : ', t.finished);      <- false
//sleep(10);
  sleep(500);
until t.finished;
writeln('2 t.finished : ', t.finished);      <- true

i guess this question is more a programming question of understanding exactly what sleep does and how it really works

what interval sleep interval shouls i use in the repeat/until to not waste cpu time needlessly

the sleep(10) gives perfect timing to end when the last thread is finished and the sleep(500) does also most of the time

but the sleep(10) is obviously running 50 times more then the sleep(500) - but i guess it depends on what the underlying 'crontab'
like interupt structure is doing.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: lucamar on July 19, 2019, 05:34:49 pm
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.

How sleep() is implemented is very platform-dependent. In Linux, IIRC, it's implemented with a call to nanosleep()

Regarding your code: you don't need to loop waiting for the thrread to terminate; you can simply call Thread.WaitFor and it won't return until it ends. Of course that will "lock" your program, but so does what you're doing now, doesn't it? So instead try this:
Code: Pascal  [Select]
  1. writeln('1 t.finished : ', t.finished);      <- false?
  2. if not t:Finished then t.WaitFor;
  3. writeln('2 t.finished : ', t.finished);      <- true?
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: ASerge 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Peter H 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 (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.)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Thaddy 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: PascalDragon 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. ;)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: lucamar 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!
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: SymbolicFrank 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Peter H 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 ;-)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Thaddy 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: PascalDragon 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: lucamar 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.)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: Peter H 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: mr-highball 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
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby 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
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: marcov 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: mr-highball 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.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on August 05, 2019, 01:48:17 am
mr-highball

Ah now it clicks what is going on - generics is in 3.1.1 and this is the latest coding stuff - so should i stay up to date with the fgl.pp from trunk or is what is in the 3.1.1 okay for this current/future generics? I can just update the fgl.pp unit right when i notice changes?

https://wiki.freepascal.org/Generics

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

btw i realized it was the fgl.pp unit that was giving the hints i was just wondering if it affected what you were coding or limited in what you could code in the ezthreads

---

i see what is happening to the links - i usually use dillo (with no javascript) to do stuff and only seamonkey (javascript) to post
the links are changed by javascript to go to where the link says it is - there is some tracking code in the link

Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: mr-highball on August 05, 2019, 01:59:28 am
toby, you should be good with 3.1.1+ since I coded this on stable (3.0.4) and have tested it with the latest trunk (3.3.1) (didn't seem to have any major breaking changes).
I plan to keep compliant with 3.0.4 generics for the foreseeable future, but I may add support for the Generics.Collections unit if I do any future work to expand the library (probably implementing more functional methods).

Hope this helps, and if you care to see any particular examples, I'd be glad to write some.
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on August 05, 2019, 02:14:26 am
mr-highball

if i might suggest why don't you start a new topoc   "Generics" and repost your

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

as first post

or does everyone know that generics is functional programming ?

https://en.wikipedia.org/wiki/Generic_programming     needs ^h^h^h^h^h has a nice fpc section for sure



Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: mr-highball on August 05, 2019, 02:45:09 am
I thought about posting a new topic for it, but I currently only have one of the functional methods implemented out of the ones listed from that topic's original post:

Are there functional programming methods in Pascal such as map, filter, apply, reduce, fold, foldl and foldr function? I could not find them on searching the internet. Possibly Pascal is a purely imperative language.

If not, is it possible to create a map function so that one can sent a list/array to it with a function and it return a new list/array with sent function applied to each element of sent list:

Code: Pascal  [Select]
  1. outlist := map(sentfunction, sentlist);

where sentfunction is a function which takes only one item and returns a modified item.

I'll probably throw something in the "third party" section once I get a few more examples out of the way so people can see some use cases

Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on August 05, 2019, 03:13:19 am
'general' might be a good place just to get something for discussion

i see you are using delphi style for the ''map' and delphi mode for the ezthreads ? are there benefits of one over the other for the generics?

are you on a windows system?


Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: mr-highball on August 05, 2019, 03:23:40 am
For me, the delphi generic syntax is preferable since I find it to be more simplified. In addition, if I wanted to port what I write cross-compiler, the delphi mode offers the easiest way to do so.

General probably is a better place to start something, so I'll most likely post something that way once I implement a few more method (sort, filter, etc...)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on August 05, 2019, 03:49:07 am

i tried to compile the map example and got
ezthreads.functional.pas(141,3) Error: Compilation raised exception internally
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: mr-highball on August 05, 2019, 03:59:08 am
The functional unit needs the latest trunk (3.3.1) to properly work, is that what you are using? If so what operating system?
(I also wrote it pretty quickly... So there are probably bugs)
Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: toby on August 05, 2019, 04:19:04 am
i have 3.1.1 on linux

i should have known you were on windows when i had to add cthreads manually to ezthreads_tester_ui.lpr (the programs ifdef unix didn't work)
3.1.1 compiles it fine and it runs fine

the 'map'   ezthreads_tester_functional.lpr requires 3.3.1




Title: Re: tthread code tthread.create/tthread,execute/constructor
Post by: PascalDragon on August 05, 2019, 09:20:48 am
The functional unit needs the latest trunk (3.3.1) to properly work, is that what you are using? If so what operating system?
(I also wrote it pretty quickly... So there are probably bugs)
Did you also test with the upcoming 3.2? After all that's going to be the next major release containing generic functions as well.