in reply to A basic 'worker' threading example.

Thanks Preceptor for a great 'template' - great for a person like me who are making my first stumbles in the world of multi-threading in perl! I have been trying to use the template and then instead of pinging, do a numeric operation and return a number. However, I cannot for my life extract the return value. In the example below, I have tried to extract the return value in a variable $sum, which is overwritten at each join... However, I get the following:

Use of uninitialized value $sum in concatenation (.) or string at test +A.pl line 26. sum= Use of uninitialized value $sum in concatenation (.) or string at test +A.pl line 26. sum=

Code:

use strict; use warnings; use threads; use Thread::Queue; my $process_q = Thread::Queue -> new(1,2); sub worker { while ( $process_q -> dequeue() ) { my $retVar=threads -> self() -> tid(); return $retVar; } } $process_q -> end(); #start some threads for ( 1..2 ) { threads -> create ( \&worker ); } #Wait for threads to all finish processing. foreach my $thr ( threads -> list() ) { my $sum=$thr -> join; print "sum=$sum\n"; }

2019-01-23 Athanasius added code and paragraph tags

Replies are listed 'Best First'.
Re^2: A basic 'worker' threading example.
by roboticus (Chancellor) on Jan 23, 2019 at 17:40 UTC

    Anonymous Monk:

    Your script is actually very close to working. The only problem is that you didn't properly set the context for the thread. (Read perldoc threads and look for the THREAD CONTEXT section. Since you didn't capture the return value of the create() call, you set up the context of the thread as VOID context, meaning that you can't fetch the return code, and that's why you're getting an undefined value later when you call join().

    So for you to fix your code, you need only set the appropriate context for the thread. Since you want a scalar result, you need only capture the result of the create() call into a scalar. That way, when you actually call the join() method, it will fetch the scalar result for you. You don't need to keep the scalar, so the simple fix for your program is to change the loop that creates your worker threads from:

    for ( 1..2 ) { threads -> create ( \&worker ); }

    to this:

    for ( 1..2 ) { my $temp_scalar = threads -> create ( \&worker ); }

    Afterwards, when you run your script, you'll get the result:

    $ perl pm_1228826.pl sum=1 sum=2

    Here, I used the 'implicit' method of setting the context. However, if you start building larger applications with different types of worker threads, you might find the explicit method of setting the context to be better. Just be sure to review the entire threads documentation and look for unexpected things. You'll also want to look over the examples and/or test code for the threads, threads::shared and Thread::Queue modules to see how their designers expect them to be used.

    Please learn how to properly quote code in a node so that people can read it more easily. I've reformatted it, made the fix I mentioned earlier, and quoted it here for other readers:

    use strict; use warnings; use threads; use Thread::Queue; my $process_q = Thread::Queue -> new(1,2); sub worker { while ( $process_q -> dequeue() ) { my $retVar=threads -> self() -> tid(); return $retVar; } } $process_q -> end(); #start some threads for ( 1..2 ) { my $tmp = threads -> create ( \&worker ); } #Wait for threads to all finish processing. foreach my $thr ( threads -> list() ) { my $sum=$thr -> join; print "sum=$sum\n"; }

    EDIT: Looks like the janitors cleaned up the formatting in the parent node before I replied.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Many thanks Roboticus for giving me a guide (and even showing how to do it), my test code is working so now I will head off to bigger and better applications! Cheers, R

Re^2: A basic 'worker' threading example.
by Anonymous Monk on Jan 23, 2019 at 10:29 UTC
    Why did you end queue?