This I have discovered recently
Jul. 14th, 2012 08:24 pmSo, I've been fiddling around with Perl, and threading.
One of the things that's been bugging me, is that when I've tried to do a 'return' from a perl subroutine, it's not worked - and I couldn't for the life of me figure out why.
What's _supposed_ to happen, is that you do 'thread -> join' to join the thread (once it's finished running) and that's supposed to capture the return result.
Why it wasn't working is thanks to this little snippet in the documentation (Yes, RTFM, I know. But to be fair, I wasn't looking for it in _that_ bit).
"The context (void, scalar or list) for the return value(s) for "->join()" is determined at the time of thread creation."
Perhaps I'd better backtrack a little though - I mean, anyone who's not really 'into' perl, might not have a clue what I'm talking about when I say 'context'.
So I shall summarise.
Perl is quite clever - it has two 'real' variable types - scalar - which contains anything that's a single value (So any string, integer, float, character, reference). And array (or list) - which is a group of zero or more scalars.
The clever bit is that it can figure out what you mean, by the context in which you do it - a brief illustration (lj cut to avoid breaking formatting).
What's happening is the rather clever function 'wantarray' is being used to tell the call context of the subroutine 'wantarray' is undefined if it's a void context (the result is discarded). True if a list/scalar context and false if in a scalar context.
As for why this is useful - consider if you do something like 'grep' - a Unix command to find 'matches' against text patterns. If you do it in a 'list' context, having a list of the lines it found would be useful. If you do it in a scalar context, then having a number of matches is probably more useful (0 being 'false' you could do 'if grep("pattern", @text_block)' for example)
So anyway - the context of a threaded subroutine is set when the thread is _created_.
Which means you need to do something like:
On the face of it, you immediately discard '$thread' because it drifts out of scope (and it does). However, it also means your thread is created in a scalar context, so any results it returns will be scalar.
If you _don't_ do this, it'll be in a void context, and any return is discarded. Which was what was tripping me up.
And you will then be able to do:
Which won't work if you don't start the thread in a scalar context.
One of the things that's been bugging me, is that when I've tried to do a 'return' from a perl subroutine, it's not worked - and I couldn't for the life of me figure out why.
What's _supposed_ to happen, is that you do 'thread -> join' to join the thread (once it's finished running) and that's supposed to capture the return result.
Why it wasn't working is thanks to this little snippet in the documentation (Yes, RTFM, I know. But to be fair, I wasn't looking for it in _that_ bit).
"The context (void, scalar or list) for the return value(s) for "->join()" is determined at the time of thread creation."
Perhaps I'd better backtrack a little though - I mean, anyone who's not really 'into' perl, might not have a clue what I'm talking about when I say 'context'.
So I shall summarise.
Perl is quite clever - it has two 'real' variable types - scalar - which contains anything that's a single value (So any string, integer, float, character, reference). And array (or list) - which is a group of zero or more scalars.
The clever bit is that it can figure out what you mean, by the context in which you do it - a brief illustration (lj cut to avoid breaking formatting).
#!/usr/bin/perl
use strict;
use warnings;
sub context_test
{
print "Called in a void context\n" unless defined wantarray();
if ( wantarray() )
{
return ( "Called in", " an array", " context" );
}
else
{
return "Called in a scalar context";
}
}
&context_test();
my $scalar_result = &context_test();
print $scalar_result;
print "\n";
my @array_result = &context_test();
print join (":", @array_result),"\n";
#And for bonus points, what does _this_ do?
print &context_test();
print "\n";
What's happening is the rather clever function 'wantarray' is being used to tell the call context of the subroutine 'wantarray' is undefined if it's a void context (the result is discarded). True if a list/scalar context and false if in a scalar context.
As for why this is useful - consider if you do something like 'grep' - a Unix command to find 'matches' against text patterns. If you do it in a 'list' context, having a list of the lines it found would be useful. If you do it in a scalar context, then having a number of matches is probably more useful (0 being 'false' you could do 'if grep("pattern", @text_block)' for example)
So anyway - the context of a threaded subroutine is set when the thread is _created_.
Which means you need to do something like:
foreach my $thing ( @list_of_things )
{
my $thread = threads -> create ( \&thing_processing_sub, $thing );
}
On the face of it, you immediately discard '$thread' because it drifts out of scope (and it does). However, it also means your thread is created in a scalar context, so any results it returns will be scalar.
If you _don't_ do this, it'll be in a void context, and any return is discarded. Which was what was tripping me up.
And you will then be able to do:
foreach my $thread ( threads -> list() )
{
my $result = $thread -> join();
print $thread -> tid(), " returned: ", $result,"\n";
}
Which won't work if you don't start the thread in a scalar context.
no subject
Date: 2012-07-19 02:02 am (UTC)no subject
Date: 2012-07-23 12:28 pm (UTC)These are denoted by the sigil '@'.
So you can do
Or alternatively - because a list is a group of scalars - this should work too:
Brackets around it means 'this is a list' - in this case, one with a single element (anything else 'fed into it' would be discarded).
Collecting the result of the thread, you can do:
(Or:
for array context.
I tend to use a construct like:
foreach my $thread ( threads -> list(threads::joinable) ) { my $result = $thread -> join(); }You can use the method 'list' without argument - It'll return a list of all running threads, and you can then call 'is_running()' or 'is_joinable()' on each if that's preferable.
I think perhaps this is worth a longer post though.
no subject
Date: 2012-07-23 12:49 pm (UTC)