How can I store per-thread state between calls in Perl?
Now from what I understand under Perl ithreads all data is private unless explicitly shared.
I want to write a function which stores per thread state between calls. I assume that a side effect of all data being thread private by default would allow me to use a closure like this:
#!/usr/bin/perl -w
use strict;
use threads;
{ # closure to create local static variable
my $per_thread_state = 0;
sub foo {
my $inc = shift;
$per_thread_开发者_开发百科state += $inc;
return $per_thread_state;
}
}
my $inc = 0;
threads->create(
sub {
my $inc = shift;
my $i = $inc;
while (--$i) {
threads->yield();
print threads->tid().":".foo($inc)."\n";
}
}, $inc
) while (++$inc < $ARGV[0]);
$_->join() foreach threads->list();
When I run it this looks like it works the way I expect, but I just want to be sure because I couldn't find any documentation which explicitly discusses doing something like this.
Could anyone point me to something official looking?
Edit
One other thing that seems strange is that the threads always seem to run in order of creation and don't interleave for some reason. For instance if I run:
./tsd.pl 100
Everything prints out perfectly in order. I'm on Ubuntu 9.04 if it matters.
Provided you're running Perl 5.9.4+, this seems like a good candidate for use of the state
keyword. If state
is enabled, only your foo()
subroutine will be able to modify the value of $per_thread_state
.
Here's how:
use feature 'state';
sub foo {
state $per_thread_state;
my $inc = shift;
$per_thread_state += $inc;
return $per_thread_state;
}
Remember to enable state
though (from perlsub):
Beginning with perl 5.9.4, you can declare variables with the state keyword in place of my. For that to work, though, you must have enabled that feature beforehand, either by using the feature pragma, or by using -E on one-liners.
perlsub also has a section on Persistent Private Variable with Closures. What you've done appears to be fine.
Your approach to creating per thread state is correct.
It often helps to think of Perl's threads as a more convenient way to deal with IPC and forked processes. Each call to threads->create(...)
clones the current interpreter, along with everything in it, so each thread will get their own independent copy of foo()
and $per_thread_state
. When you join a thread, you can pass back a value, but everything else in the state of the thread's interpreter will be destroyed.
Your threads are running in creation order largely due to implementation details in Perl and the operating system (mainly because their individual execution time is below the operating system's shortest execution-time slice). To interleave the threads, you can use sleep
rather than yield (or make the threads do some real work).
精彩评论