=head1 DESCRIPTION
B<NOTE>: this tutorial describes the new Perl threading flavour
-introduced in Perl 5.6.0 called interpreter threads, or ithreads
-for short. There is another older Perl threading flavour called
-the 5.005 model, unsurprisingly for 5.005 versions of Perl.
-The old model is deprecated, and will probably be removed around release
-5.10. You are strongly encouraged to migrate any existing 5.005 threads
-code to the new model as soon as possible.
+introduced in Perl 5.6.0 called interpreter threads, or B<ithreads>
+for short. In this model each thread runs in its own Perl interpreter,
+and any data sharing between threads must be explicit.
+
+There is another older Perl threading flavour called the 5.005 model,
+unsurprisingly for 5.005 versions of Perl. The old model is known to
+have problems, deprecated, and will probably be removed around release
+5.10. You are strongly encouraged to migrate any existing 5.005
+threads code to the new model as soon as possible.
You can see which (or neither) threading flavour you have by
running C<perl -V> and looking at the C<Platform> section.
The ithreads code has been available since Perl 5.6.0, and is considered
stable. The user-level interface to ithreads (the L<threads> classes)
-appeared in the 5.8.0 release, and as of this time is considered stable,
-although as with all new features, should be treated with caution.
+appeared in the 5.8.0 release, and as of this time is considered stable
+although it should be treated with caution as with all new features.
=head1 What Is A Thread Anyway?
do things unless your operating systems threads allows it. So if your
system blocks the entire process on sleep(), Perl usually will as well.
+Perl Threads Are Different.
+
=head1 Threadsafe Modules
The addition of threads has changed Perl's internals
If you're using a module that's not thread-safe for some reason, you
can protect yourself by using semaphores and lots of programming
discipline to control access to the module. Semaphores are covered
-later in the article. Perl Threads Are Different
+later in the article.
+
+See also L</"Threadsafety of System Libraries">.
=head1 Thread Basics
enabled. If your program can't run without them, you can say something
like:
- $Config{useithreads} or die "Recompile Perl with threads to run this program.";
+ $Config{useithreads} or die "Recompile Perl with threads to run this program.";
A possibly-threaded program using a possibly-threaded module might
have code like this:
use Config;
use MyMod;
- if ($Config{useithreads}) {
- # We have threads
- require MyMod_threaded;
- import MyMod_threaded;
- } else {
- require MyMod_unthreaded;
- import MyMod_unthreaded;
+ BEGIN {
+ if ($Config{useithreads}) {
+ # We have threads
+ require MyMod_threaded;
+ import MyMod_threaded;
+ } else {
+ require MyMod_unthreaded;
+ import MyMod_unthreaded;
+ }
}
Since code that runs both with and without threads is usually pretty
module. In our example above, that's what MyMod_threaded is, and it's
only imported if we're running on a threaded Perl.
+=head2 A Note about the Examples
+
+Although thread support is considered to be stable, there are still a number
+of quirks that may startle you when you try out any of the examples below.
+In a real situation, care should be taken that all threads are finished
+executing before the program exits. That care has B<not> been taken in these
+examples in the interest of simplicity. Running these examples "as is" will
+produce error messages, usually caused by the fact that there are still
+threads running when the program exits. You should not be alarmed by this.
+Future versions of Perl may fix this problem.
+
=head2 Creating Threads
The L<threads> package provides the tools you need to create new
-threads. Like any other module, you need to tell Perl you want to use
+threads. Like any other module, you need to tell Perl that you want to use
it; C<use threads> imports all the pieces you need to create basic
threads.
-The simplest, straightforward way to create a thread is with new():
+The simplest, most straightforward way to create a thread is with new():
use threads;
$Param3 = "foo";
$thr = threads->new(\&sub1, "Param 1", "Param 2", $Param3);
$thr = threads->new(\&sub1, @ParamList);
- $thr = threads->new(\&sub1, qw(Param1 Param2 $Param3));
+ $thr = threads->new(\&sub1, qw(Param1 Param2 Param3));
sub sub1 {
my @InboundParameters = @_;
the same subroutine, but in a separate thread with a separate
environment and potentially separate arguments.
-C<create()> is a synonym for C<new()>
+C<create()> is a synonym for C<new()>.
=head2 Giving up control
There are times when you may find it useful to have a thread
explicitly give up the CPU to another thread. Your threading package
might not support preemptive multitasking for threads, for example, or
-you may be doing something compute-intensive and want to make sure
+you may be doing something processor-intensive and want to make sure
that the user-interface thread gets called frequently. Regardless,
there are times that you might want a thread to give up the processor.
this. yield() is pretty straightforward, and works like this:
use threads;
-
+
sub loop {
my $thread = shift;
my $foo = 50;
while($foo--) { print "in thread $thread\n" }
- threads->yield();
+ threads->yield;
$foo = 50;
while($foo--) { print "in thread $thread\n" }
}
my $thread1 = threads->new(\&loop, 'first');
my $thread2 = threads->new(\&loop, 'second');
my $thread3 = threads->new(\&loop, 'third');
-
+
It is important to remember that yield() is only a hint to give up the CPU,
it depends on your hardware, OS and threading libraries what actually happens.
Therefore it is important to note that one should not build the scheduling of
}
}
-
Once a thread is detached, it may not be joined, and any return data
that it might have produced (if it was done and waiting for a join) is
lost.
except that in this case, the data is just copied to a different part of
memory within the same process rather than a real fork taking place.
-To make use of threading however, one usually want the threads to share
+To make use of threading however, one usually wants the threads to share
at least some data between themselves. This is done with the
L<threads::shared> module and the C< : shared> attribute:
my $foo : shared = 1;
my $bar = 1;
threads->new(sub { $foo++; $bar++ })->join;
-
+
print "$foo\n"; #prints 2 since $foo is shared
print "$bar\n"; #prints 1 since $bar is not shared
... create some threads ...
$hash{a} = 1; # all threads see exists($hash{a}) and $hash{a} == 1
- $hash{a} = $var # okay - copy-by-value: same affect as previous
- $hash{a} = $svar # okay - copy-by-value: same affect as previous
+ $hash{a} = $var # okay - copy-by-value: same effect as previous
+ $hash{a} = $svar # okay - copy-by-value: same effect as previous
$hash{a} = \$svar # okay - a reference to a shared variable
$hash{a} = \$var # This will die
delete $hash{a} # okay - all threads will see !exists($hash{a})
my $c : shared;
my $thr1 = threads->create(sub { $b = $a; $a = $b + 1; });
my $thr2 = threads->create(sub { $c = $a; $a = $c + 1; });
- $thr1->join();
- $thr2->join();
+ $thr1->join;
+ $thr2->join;
Two threads both access $a. Each thread can potentially be interrupted
at any point, or be executed in any order. At the end, $a could be 3
between themselves and their data, to avoid race conditions and the like.
Some of these are designed to resemble the common techniques used in thread
libraries such as C<pthreads>; others are Perl-specific. Often, the
-standard techniques are clumsily and difficult to get right (such as
+standard techniques are clumsy and difficult to get right (such as
condition waits). Where possible, it is usually easier to use Perlish
techniques such as queues, which remove some of the hard work involved.
The lock() function takes a shared variable and puts a lock on it.
No other thread may lock the variable until the the variable is unlocked
by the thread holding the lock. Unlocking happens automatically
-when the locking thread exists the outermost block that contains
+when the locking thread exits the outermost block that contains
C<lock()> function. Using lock() is straightforward: this example has
several threads doing some calculations in parallel, and occasionally
updating a running total:
# (... do some calculations and set $result ...)
{
lock($total); # block until we obtain the lock
- $total += $result
+ $total += $result;
} # lock implicitly released at end of scope
last if $result == 0;
}
{
{
lock($x); # wait for lock
- lock($x): # NOOP - we already have the lock
+ lock($x); # NOOP - we already have the lock
{
lock($x); # NOOP
{
use threads;
use threads::shared::queue;
- my $DataQueue = threads::shared::queue->new();
+ my $DataQueue = threads::shared::queue->new;
$thr = threads->new(sub {
while ($DataElement = $DataQueue->dequeue) {
print "Popped $DataElement off the queue\n";
$DataQueue->enqueue(\$thr);
sleep 10;
$DataQueue->enqueue(undef);
- $thr->join();
+ $thr->join;
You create the queue with C<new threads::shared::queue>. Then you can
add lists of scalars onto the end with enqueue(), and pop scalars off
}
}
- $thr1->join();
- $thr2->join();
- $thr3->join();
+ $thr1->join;
+ $thr2->join;
+ $thr3->join;
The three invocations of the subroutine all operate in sync. The
semaphore, though, makes sure that only one thread is accessing the
$semaphore->up(5); # Increment the counter by five
}
- $thr1->detach();
- $thr2->detach();
+ $thr1->detach;
+ $thr2->detach;
If down() attempts to decrement the counter below zero, it blocks until
the counter is large enough. Note that while a semaphore can be created
14 }
15
16 $stream->enqueue(undef);
- 17 $kid->join();
+ 17 $kid->join;
18
19 sub check_num {
20 my ($upstream, $cur_prime) = @_;
30 }
31 }
32 $downstream->enqueue(undef) if $kid;
- 33 $kid->join() if $kid;
+ 33 $kid->join if $kid;
34 }
This program uses the pipeline model to generate prime numbers. Each
thread in the pipeline has an input queue that feeds numbers to be
checked, a prime number that it's responsible for, and an output queue
-that into which it funnels numbers that have failed the check. If the thread
+into which it funnels numbers that have failed the check. If the thread
has a number that's failed its check and there's no child thread, then
the thread must have found a new prime number. In that case, a new
child thread is created for that prime and stuck on the end of the
=head1 Threadsafety of System Libraries
Whether various library calls are threadsafe is outside the control
-of Perl. Calls often suffering from not being threadsafe include
+of Perl. Calls often suffering from not being threadsafe include:
localtime(), gmtime(), get{gr,host,net,proto,serv,pw}*(), readdir(),
-rand(), srand(). If the system Perl is compiled in has threadsafe
-variants of these calls, they will be used, but besides that, Perl is
-at the mercy of the thread safety or unsafety of the calls. Please
-consult your C library call documentation.
+rand(), and srand() -- in general, calls that depend on some external
+state.
+
+If the system Perl is compiled in has threadsafe variants of such
+calls, they will be used. Beyond that, Perl is at the mercy of
+the threadsafety or unsafety of the calls. Please consult your
+C library call documentation.
+
+In some platforms the threadsafe interfaces may fail if the result
+buffer is too small (for example getgrent() may return quite large
+group member lists). Perl will retry growing the result buffer
+a few times, but only up to 64k (for safety reasons).
=head1 Conclusion
France, September 1992, Yves Bekkers and Jacques Cohen, eds. Springer,
1992, ISBN 3540-55940-X (real-life thread applications).
+Artur Bergman, "Where Wizards Fear To Tread", June 11, 2002,
+L<http://www.perl.com/pub/a/2002/06/11/threads.html>
+
=head1 Acknowledgements
Thanks (in no particular order) to Chaim Frenkel, Steve Fink, Gurusamy
=head1 AUTHOR
-Dan Sugalski E<lt>sugalskd@ous.eduE<gt>
+Dan Sugalski E<lt>dan@sidhe.org<gt>
Slightly modified by Arthur Bergman to fit the new thread model/module.