Recent

Author Topic: ezthreads  (Read 6343 times)

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
ezthreads
« on: September 02, 2018, 07:06:00 am »
Hello all,

I've written a library that may be useful if you need to work with threads.

https://github.com/mr-highball/ezthreads

It's still very much a work in progress, so things may change, but it works similar to delphi's anonymous methods in that, an ezthread is reference counted and allows "capturing" any number of variables to pass to the thread for process. Below is a simple example I've pulled from the tester application. Note that nested methods are used, but there are overloads for both methods "of object" and standard callbacks.

Quote
{$modeswitch nestedprocvars}

...

(*
  an example showing how to use dynamic input and perform some
  arbitrary calculation with it in an ezthread
*)
procedure TestDynInput;
var
  LThread:IEZThread;

  (*
    adds two numbers and returns
  *)
  function Add(A,B:Integer):Integer;
  begin
    Result:=A + B;
  end;

  (*
    setup method (runs in separate thread)
  *)
  procedure Setup(Const AThread:IEZThread);
  begin
    AThread.AddArg('result',Add(AThread['A'],AThread['B']));
  end;

  (*
    method to run once thread work has finished (runs in main caller's thread)
  *)
  procedure Print(Const AThread:IEZThread);
  begin
    WriteLn('TestDynInput::Result=' + IntToStr(AThread['result']));
  end;

begin
  LThread:=TEZThreadImpl.Create;
  LThread
    .AddArg('A',1)
    .AddArg('B',2)
    .Events
      .UpdateOnStopNestedCallback(Print)
      .Thread
    .Setup(Setup)
    .Start;
end;

tr_escape

  • Sr. Member
  • ****
  • Posts: 432
  • sector name toys | respect to spectre
    • Github:
Re: ezthreads
« Reply #1 on: September 02, 2018, 04:15:34 pm »
Hello I just try to execute of the example project but it gives that message:

ezthreads.pas(761,47) Error: Illegal type conversion: "Variant" to "NativeInt"

I am using ;
Lazarus 1.9.0 r58680 FPC 3.1.1 i386-linux-gtk2

Maybe I need some flag on or off?

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: ezthreads
« Reply #2 on: September 02, 2018, 04:34:18 pm »
ezthreads.pas(761,47) Error: Illegal type conversion: "Variant" to "NativeInt"
Variants in a thread lib?, Mhmmm, doesn't sound too useful, because a variant is usually multiple times slower than locking or synchronizing.
Or is that your code, tr_escape?
Specialize a type, not a var.

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #3 on: September 02, 2018, 04:35:27 pm »
Hello I just try to execute of the example project but it gives that message:

ezthreads.pas(761,47) Error: Illegal type conversion: "Variant" to "NativeInt"

I am using ;
Lazarus 1.9.0 r58680 FPC 3.1.1 i386-linux-gtk2

Maybe I need some flag on or off?

Thank you for testing, I haven't been able to try on anything other than windows yet. Internally ezthreads stores a pointer to an object as a NativeInt, then casts back to the object to work with it.

line:761
Code: Pascal  [Select][+][-]
  1. LLIntThread:=TInternalThread({%H-}Pointer(NativeInt(AThread[MON_THREAD]))^);

The warning for this code being portable was suppressed because what I've read, NativeInt is the proper size of a pointer on different platforms.
I'll do some more research and see about spinning up a linux vm to test with.

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: ezthreads
« Reply #4 on: September 02, 2018, 04:37:10 pm »
@mr-highball
What caused the variant? Your code or tr_escape's code? I can't test right now, but the use of variants does not belong in a thread library.
It slows things down. Also, variants are not threadsafe by default.
« Last Edit: September 02, 2018, 04:40:10 pm by Thaddy »
Specialize a type, not a var.

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #5 on: September 02, 2018, 04:41:27 pm »
ezthreads.pas(761,47) Error: Illegal type conversion: "Variant" to "NativeInt"
Variants in a thread lib?, Mhmmm, doesn't sound too useful, because a variant is usually multiple times slower than locking or synchronizing.
Or is that your code, tr_escape?

It is my code, and variants were chosen as a convenience over speed. It allows "most" types to be passed in to be used by the threads without much trouble for the caller. Generics were sort of ruled out since forward declaring of generic interfaces isn't supported.

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #6 on: September 02, 2018, 04:50:48 pm »
@Thaddy
the library allows for adding/updating arguments by name to be used by the thread method (and various events/callbacks) which are variants.

in this example, we pass two numbers to work with:
https://github.com/mr-highball/ezthreads/blob/master/test/ezthreads_tester.lpr#L183

while in this one, a string is used:
https://github.com/mr-highball/ezthreads/blob/master/test/ezthreads_tester.lpr#L126

tr_escape

  • Sr. Member
  • ****
  • Posts: 432
  • sector name toys | respect to spectre
    • Github:
Re: ezthreads
« Reply #7 on: September 02, 2018, 05:41:23 pm »
I changed this line :

LLIntThread:=TInternalThread({%H-}Pointer(NativeInt(AThread[MON_THREAD]))^);

to

LLIntThread:=TInternalThread({%H-}Pointer(Integer(AThread[MON_THREAD]))^);

It is compiled for windows and I test it with by wine :
Code: Pascal  [Select][+][-]
  1. xx@xx-pc:~/Belgeler/GitProjects/ezthreads-master/test$ wine ezthreads_tester.exe
  2. TestAddrArg::success
  3. hello world from an ezthread! MainThreadID:9 EZThreadID:47
  4. TestHelloWorld::success, waiting no longer
  5.  
  6. // Also native linux console result:
  7.  
  8. xx@xx-pc:~/Belgeler/GitProjects/ezthreads-master/test$ ./ezthreads_tester
  9. TestAddrArg::success
  10. hello world from an ezthread! MainThreadID:-1209177792 EZThreadID:-1211434176
  11. TestHelloWorld::success, waiting no longer
  12. TestDynInput::Result=3
  13.  
  14. xx@xx-pc:~/Belgeler/GitProjects/ezthreads-master/test$

But maybe you should work on linux directly for linux users.

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #8 on: September 02, 2018, 05:52:28 pm »
Thank you for posting results @tr_escape
From what I'm seeing NativeInt is typed to PtrInt, which what I'm reading should be the safe way to do this sort of casting. Maybe someone else here would have some insight? It may be a bit before I can get a linux vm up to fiddle around...

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: ezthreads
« Reply #9 on: September 02, 2018, 05:56:25 pm »
Thank you for posting results @tr_escape
From what I'm seeing NativeInt is typed to PtrInt, which what I'm reading should be the safe way to do this sort of casting. Maybe someone else here would have some insight? It may be a bit before I can get a linux vm up to fiddle around...
just a thought, doesn't variant already support pointer variables and if yes what is the point of casting back and forth to integer?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #10 on: September 02, 2018, 06:06:48 pm »
Thank you for posting results @tr_escape
From what I'm seeing NativeInt is typed to PtrInt, which what I'm reading should be the safe way to do this sort of casting. Maybe someone else here would have some insight? It may be a bit before I can get a linux vm up to fiddle around...
just a thought, doesn't variant already support pointer variables and if yes what is the point of casting back and forth to integer?

I thought so as well, but when the code is:
Code: Pascal  [Select][+][-]
  1. LLIntThread:=TInternalThread({%H-}Pointer(AThread[MON_THREAD])^);


this compiler error occurs:
Quote
ezthreads.pas(761,39) Error: Illegal type conversion: "Variant" to "Pointer"

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: ezthreads
« Reply #11 on: September 02, 2018, 06:57:06 pm »
@Thaddy
the library allows for adding/updating arguments by name to be used by the thread method (and various events/callbacks) which are variants.
Ok. That save me testing it. It does not fit in my application universe if it uses variants. But others may still benefit if it is well written...
Specialize a type, not a var.

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #12 on: September 09, 2018, 03:21:25 am »
a good bit of refactoring on the internals, and a few tweaks to the samples, changes detailed in this pull request:

https://github.com/mr-highball/ezthreads/pull/1

also should fix @tr_escape's issue on linux since there are no longer any wonky nativeint -> pointer -> object casts. Also to address @Thaddy's concern about variants, they are completely optional. The only time variants are used is when a caller uses the .AddArg() method, so if that is not called the caller would still gain the conveniences that ezthread provides.

mr-highball

  • Full Member
  • ***
  • Posts: 233
    • Highball Github
Re: ezthreads
« Reply #13 on: October 16, 2018, 09:08:30 pm »
Hello all, I've added a bit more features to ezthreads detailed in this pull request:

https://github.com/mr-highball/ezthreads/pull/2

specifically, I've added an Await() method which acts similar to the c# await operator, in that it will block until specific conditions are met. There are overloads for:
  • block until all running ezthreads at that point in time have finished
  • block until all threads in a specific thread group have finished
  • block until a specific thread has finished

here is a sample pulled from the testing console application using this:
Code: Pascal  [Select][+][-]
  1. (*
  2.   this test sets up a situation where one thread (B) depends
  3.   on another thread (A) to finish before it can proceed to process.
  4.   lastly this method blocks until both thread (A) & (B) finish using
  5.   await
  6. *)
  7. procedure TestThreadDependency;
  8. var
  9.   LThreadA,
  10.   LThreadB:IEZThread;
  11.  
  12.   procedure MethodA(Const AThread:IEZThread);
  13.   begin
  14.     //do some important work
  15.     WriteLn('TestThreadDependency::ThreadA starting');
  16.     Sleep(1000);
  17.     WriteLn('TestThreadDependency::ThreadA finished');
  18.   end;
  19.  
  20.   procedure MethodB(Const AThread:IEZThread);
  21.   var
  22.     LID:String;
  23.   begin
  24.     LID:=AThread['id'];
  25.  
  26.     //write that we got to thread (B)
  27.     WriteLn('TestThreadDependency::ThreadB starting');
  28.  
  29.     //before doing our work, wait until thread (A) has completed
  30.     Await(LID);
  31.  
  32.     //write to console that we finished
  33.     WriteLn('TestThreadDependency::ThreadB finished');
  34.   end;
  35.  
  36. begin
  37.   //init both threads
  38.   LThreadA:=TEZThreadImpl.Create;
  39.   LThreadB:=TEZThreadImpl.Create;
  40.  
  41.   //setup thread (A)
  42.   LThreadA
  43.     .Setup(MethodA)
  44.     .Start;
  45.  
  46.   //below we add the thread group id of (A) so that thread (B) can
  47.   //"await" until (A) is done to proceed its task
  48.   LThreadB
  49.     .AddArg('id',LThreadA.Settings.Await.GroupID)
  50.     .Setup(MethodB)
  51.     .Start;
  52.  
  53.   //wait for all threads
  54.   Await;
  55. end;
  56.  

Happy threading  :)

 

TinyPortal © 2005-2018