http://qs321.pair.com?node_id=377214

beable has asked for the wisdom of the Perl Monks concerning the following question:

Is returning a list broken when using threads? I find the difference in behaviour between calling a subroutine which returns a list in a thread and calling the subroutine directly hard to understand. When calling the subroutine with a thread, I'm only getting the last element of the list back. When I call the subroutine without a thread, I get the whole list. What's going on? The code below is mostly from perlthrtut.

#!/usr/bin/perl use threads; $thr = threads->new(\&sub1); @ReturnData = $thr->join; print "Thread returned @ReturnData\n"; print "array size is: ", scalar(@ReturnData), "\n"; @ReturnData = sub1(); print "Subroutine returned @ReturnData\n"; print "array size is: ", scalar(@ReturnData), "\n"; sub sub1 { return ("Fifty-six", "foo", 23); } __END__ Output: Thread returned 23 array size is: 1 Subroutine returned Fifty-six foo 23 array size is: 3

Replies are listed 'Best First'.
Re: Is returning a list broken when using threads?
by Errto (Vicar) on Jul 25, 2004 at 02:36 UTC

    I haven't used threads before, but I found the following in perldoc threads for Perl 5.8.3 (typo corrected):

    The context (scalar or list) of the thread creation is also the context for join(). This means that if you intend to return an array from a thread, you must use "my ($thread) = threads->new(...)", and that if you intend to return a scalar, you must use "my $thread = ...".

    Now that I think about it, it kinda has to be that way. It can't use the context for the join call, because that's too late. The called routine has to be able to invoke wantarray from the moment it's called and get the right result.

      Riiiiight, so this example from perlthrtut is rather misleading then:
      Waiting For A Thread To Exit Since threads are also subroutines, they can return values. To wait for a thread to exit and extract any values it might return, you can use the join() method: use threads; $thr = threads->new(\&sub1); @ReturnData = $thr->join; print "Thread returned @ReturnData"; sub sub1 { return "Fifty-six", "foo", 2; } In the example above, the join() method returns as soon as the thread ends. In addition to waiting for a thread to finish and gathering up any values that the thread might have returned, join() also performs any OS cleanup necessary for the thread. That cleanup might be impor- tant, especially for long-running programs that spawn lots of threads. If you don't want the return values and don't want to wait for the thread to finish, you should call the detach() method instead, as described next.
      Thanks!

        I think the problem with perlthrtut and some other bits of the documentation (what there is of it), was mostly written for 5005threads and hasn't really caught up with ithreads yet.

        That said. I'm not sure how the snippet you quote would have worked then either.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
        Patches are welcome. (Appreciated even.)
Re: Is returning a list broken when using threads?
by pg (Canon) on Jul 25, 2004 at 16:30 UTC

    To make this discussion complete, on the other hand, most of the time, it is a better idea to return array ref, instead of array, regardless whether the program is multi-threaded: (In this way, you don't need to worry about the context any more)

    use strict; use warnings; use Data::Dumper; use threads; my $thr = threads->new(\&sub1); my $ReturnData = $thr->join; print Dumper($ReturnData); $ReturnData = sub1(); print Dumper($ReturnData); sub sub1 { return ["Fifty-six", "foo", 23]; }

    This prints:

    $VAR1 = [ 'Fifty-six', 'foo', 23 ]; $VAR1 = [ 'Fifty-six', 'foo', 23 ];
Re: Is returning a list broken when using threads?
by pg (Canon) on Jul 25, 2004 at 20:53 UTC

    Sort of triggered by what CountZero and chromatic said, I tried this:

    use strict; use warnings; use Data::Dumper; use threads; { my @ReturnData = sub1(); print Dumper(@ReturnData); } { my $ReturnData = sub1(); print Dumper($ReturnData); } { my $thr = threads->new(\&sub1); my @ReturnData = $thr->join; print Dumper(@ReturnData); } { my $thr = threads->new(\&sub1); my $ReturnData = $thr->join; print Dumper($ReturnData); } { my ($thr) = threads->new(\&sub1); my @ReturnData = $thr->join; print Dumper(@ReturnData); } { my ($thr) = threads->new(\&sub1); my $ReturnData = $thr->join; print Dumper($ReturnData); } sub sub1 { return wantarray ? (1,2,3) : [4,5,6]; }

    Results:

    $VAR1 = 1; $VAR2 = 2; $VAR3 = 3; $VAR1 = [ 4, 5, 6 ]; $VAR1 = [ 4, 5, 6 ]; $VAR1 = [ 4, 5, 6 ]; $VAR1 = 1; $VAR2 = 2; $VAR3 = 3; $VAR1 = 3;

    The result makes 100% sense under the current design, as it matches what the document said, the context (whether wantarray) has been already determined at the thread creation time.