Perl Threads Are Different.
-=head1 Threadsafe Modules
+=head1 Thread-Safe Modules
-The addition of threads has changed Perl's internals
+The addition of threads has changed Perl's internals
substantially. There are implications for people who write
-modules with XS code or external libraries. However, since the threads
-do not share data, pure Perl modules that don't interact with external
-systems should be safe. Modules that are not tagged as thread-safe should
-be tested or code reviewed before being used in production code.
+modules with XS code or external libraries. However, since perl data is
+not shared among threads by default, Perl modules stand a high chance of
+being thread-safe or can be made thread-safe easily. Modules that are not
+tagged as thread-safe should be tested or code reviewed before being used
+in production code.
Not all modules that you might use are thread-safe, and you should
always assume a module is unsafe unless the documentation says
core. Threads are a new feature, and even some of the standard
modules aren't thread-safe.
-Even if a module is threadsafe, it doesn't mean that the module is optimized
+Even if a module is thread-safe, it doesn't mean that the module is optimized
to work well with threads. A module could possibly be rewritten to utilize
the new features in threaded Perl to increase performance in a threaded
environment.
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.
+can protect yourself by using it from one, and only one thread at all.
+If you need multiple threads to access such a module, you can use semaphores and
+lots of programming discipline to control access to it. Semaphores
+are covered in L</"Basic semaphores">.
-See also L</"Threadsafety of System Libraries">.
+See also L</"Thread-Safety of System Libraries">.
=head1 Thread Basics
A possibly-threaded program using a possibly-threaded module might
have code like this:
- use Config;
- use MyMod;
+ use Config;
+ use MyMod;
BEGIN {
- if ($Config{useithreads}) {
- # We have threads
- require MyMod_threaded;
- import MyMod_threaded;
- } else {
- require MyMod_unthreaded;
- import MyMod_unthreaded;
+ 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
messy, it's best to isolate the thread-specific code in its own
$thr->detach; # Now we officially don't care any more
- sub sub1 {
+ sub sub1 {
$a = 0;
while (1) {
$a++;
=head2 Controlling access: lock()
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
+No other thread may lock the variable until the variable is unlocked
by the thread holding the lock. Unlocking happens automatically
when the locking thread exits the outermost block that contains
C<lock()> function. Using lock() is straightforward: this example has
this:
use threads;
- use threads::shared::queue;
+ use Thread::Queue;
- my $DataQueue = threads::shared::queue->new;
+ my $DataQueue = Thread::Queue->new;
$thr = threads->new(sub {
while ($DataElement = $DataQueue->dequeue) {
print "Popped $DataElement off the queue\n";
$DataQueue->enqueue(undef);
$thr->join;
-You create the queue with C<new threads::shared::queue>. Then you can
+You create the queue with C<new Thread::Queue>. Then you can
add lists of scalars onto the end with enqueue(), and pop scalars off
the front of it with dequeue(). A queue has no fixed size, and can grow
as needed to hold everything pushed on to it.
gives a quick demonstration:
use threads qw(yield);
- use threads::shared::semaphore;
+ use Thread::Semaphore;
- my $semaphore = new threads::shared::semaphore;
+ my $semaphore = new Thread::Semaphore;
my $GlobalVariable : shared = 0;
$thr1 = new threads \&sample_sub, 1;
of these defaults simply by passing in different values:
use threads;
- use threads::shared::semaphore;
- my $semaphore = threads::shared::semaphore->new(5);
+ use Thread::Semaphore;
+ my $semaphore = Thread::Semaphore->new(5);
# Creates a semaphore with the counter set to five
$thr1 = threads->new(\&sub1);
4 use strict;
5
6 use threads;
- 7 use threads::shared::queue;
+ 7 use Thread::Queue;
8
- 9 my $stream = new threads::shared::queue;
+ 9 my $stream = new Thread::Queue;
10 my $kid = new threads(\&check_num, $stream, 2);
11
12 for my $i ( 3 .. 1000 ) {
19 sub check_num {
20 my ($upstream, $cur_prime) = @_;
21 my $kid;
- 22 my $downstream = new threads::shared::queue;
+ 22 my $downstream = new Thread::Queue;
23 while (my $num = $upstream->dequeue) {
24 next unless $num % $cur_prime;
25 if ($kid) {
Also note that under the current implementation, shared variables
use a little more memory and are a little slower than ordinary variables.
-=head1 Threadsafety of System Libraries
+=head1 Process-scope Changes
+
+Note that while threads themselves are separate execution threads and
+Perl data is thread-private unless explicitly shared, the threads can
+affect process-scope state, affecting all the threads.
+
+The most common example of this is changing the current working
+directory using chdir(). One thread calls chdir(), and the working
+directory of all the threads changes.
+
+Even more drastic example of a process-scope change is chroot():
+the root directory of all the threads changes, and no thread can
+undo it (as opposed to chdir()).
-Whether various library calls are threadsafe is outside the control
-of Perl. Calls often suffering from not being threadsafe include:
+Further examples of process-scope changes include umask() and
+changing uids/gids.
+
+Thinking of mixing fork() and threads? Please lie down and wait
+until the feeling passes-- but in case you really want to know,
+the semantics is that fork() duplicates all the threads.
+(In UNIX, at least, other platforms will do something different.)
+
+Similarly, mixing signals and threads should not be attempted.
+Implementations are platform-dependent, and even the POSIX
+semantics may not be what you expect (and Perl doesn't even
+give you the full POSIX API).
+
+=head1 Thread-Safety of System Libraries
+
+Whether various library calls are thread-safe is outside the control
+of Perl. Calls often suffering from not being thread-safe include:
localtime(), gmtime(), get{gr,host,net,proto,serv,pw}*(), readdir(),
-rand(), and srand() -- in general, calls that depend on some external
-state.
+rand(), and srand() -- in general, calls that depend on some global
+external state.
-If the system Perl is compiled in has threadsafe variants of such
+If the system Perl is compiled in has thread-safe 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
+the thread-safety 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).
+On some platforms the thread-safe library interfaces may fail if the
+result buffer is too small (for example the user group databases may
+be rather large, and the reentrant interfaces may have to carry around
+a full snapshot of those databases). Perl will start with a small
+buffer, but keep retrying and growing the result buffer
+until the result fits. If this limitless growing sounds bad for
+security or memory consumption reasons you can recompile Perl with
+PERL_REENTRANT_MAXSIZE defined to the maximum number of bytes you will
+allow.
=head1 Conclusion
Arnold, Ken and James Gosling. The Java Programming Language, 2nd
ed. Addison-Wesley, 1998, ISBN 0-201-31006-6.
+comp.programming.threads FAQ,
+L<http://www.serpentine.com/~bos/threads-faq/>
+
Le Sergent, T. and B. Berthomieu. "Incremental MultiThreaded Garbage
Collection on Virtually Shared Memory Architectures" in Memory
Management: Proc. of the International Workshop IWMM 92, St. Malo,
Slightly modified by Arthur Bergman to fit the new thread model/module.
+Reworked slightly by Jörg Walter E<lt>jwalt@cpan.org<gt> to be more concise
+about thread-safety of perl code.
+
=head1 Copyrights
The original version of this article originally appeared in The Perl