X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2Fthreads%2Fthreads.pm;h=6bf15d04d491faaadb6de53d1b1ddbe71a23a694;hb=5e137bc214f9c21ed33df8110b67005fb915c4e7;hp=39416d3db9c5661f3259c4b92fc722485b6470b9;hpb=f2e0bb91ca7c0e6f975c2a54cb50ff00d953561c;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/threads/threads.pm b/ext/threads/threads.pm index 39416d3..6bf15d0 100755 --- a/ext/threads/threads.pm +++ b/ext/threads/threads.pm @@ -5,31 +5,27 @@ use 5.008; use strict; use warnings; -our $VERSION = '1.29'; +our $VERSION = '1.71'; my $XS_VERSION = $VERSION; $VERSION = eval $VERSION; +# Verify this Perl supports threads +require Config; +if (! $Config::Config{useithreads}) { + die("This Perl not built to support threads\n"); +} -BEGIN { - # Verify this Perl supports threads - use Config; - if (! $Config{useithreads}) { - die("This Perl not built to support threads\n"); - } - - # Declare that we have been loaded - $threads::threads = 1; - - # Complain if 'threads' is loaded after 'threads::shared' - if ($threads::shared::threads_shared) { - warn <<'_MSG_'; +# Complain if 'threads' is loaded after 'threads::shared' +if ($threads::shared::threads_shared) { + warn <<'_MSG_'; Warning, threads::shared has already been loaded. To enable shared variables, 'use threads' must be called before threads::shared or any module that uses it. _MSG_ - } } +# Declare that we have been loaded +$threads::threads = 1; # Load the XS code require XSLoader; @@ -47,14 +43,27 @@ sub import # Handle args while (my $sym = shift) { - if ($sym =~ /^stack/) { - threads->set_stack_size(shift); - - } elsif ($sym =~ /all/) { + if ($sym =~ /^(?:stack|exit)/i) { + if (defined(my $arg = shift)) { + if ($sym =~ /^stack/i) { + threads->set_stack_size($arg); + } else { + $threads::thread_exit_only = $arg =~ /^thread/i; + } + } else { + require Carp; + Carp::croak("threads: Missing argument for option: $sym"); + } + + } elsif ($sym =~ /^str/i) { + import overload ('""' => \&tid); + + } elsif ($sym =~ /^(?::all|yield)$/) { push(@EXPORT, qw(yield)); } else { - push(@EXPORT, $sym); + require Carp; + Carp::croak("threads: Unknown import option: $sym"); } } @@ -74,6 +83,29 @@ sub import ### Methods, etc. ### +# Exit from a thread (only) +sub exit +{ + my ($class, $status) = @_; + if (! defined($status)) { + $status = 0; + } + + # Class method only + if (ref($class)) { + require Carp; + Carp::croak('Usage: threads->exit(status)'); + } + + $class->set_thread_exit_only(1); + CORE::exit($status); +} + +# 'Constant' args for threads->list() +sub threads::all { } +sub threads::running { 1 } +sub threads::joinable { 0 } + # 'new' is an alias for 'create' *new = \&create; @@ -102,52 +134,91 @@ threads - Perl interpreter-based threads =head1 VERSION -This document describes threads version 1.29 +This document describes threads version 1.71 =head1 SYNOPSIS - use threads ('yield', 'stack_size' => 64*4096); + use threads ('yield', + 'stack_size' => 64*4096, + 'exit' => 'threads_only', + 'stringify'); sub start_thread { my @args = @_; - print "Thread started: @args\n"; + print('Thread started: ', join(' ', @args), "\n"); } - my $thread = threads->create('start_thread', 'argument'); - $thread->join(); + my $thr = threads->create('start_thread', 'argument'); + $thr->join(); threads->create(sub { print("I am a thread\n"); })->join(); - my $thread3 = async { foreach (@files) { ... } }; - $thread3->join(); + my $thr2 = async { foreach (@files) { ... } }; + $thr2->join(); + if (my $err = $thr2->error()) { + warn("Thread error: $err\n"); + } - # Invoke thread in list context so it can return a list + # Invoke thread in list context (implicit) so it can return a list my ($thr) = threads->create(sub { return (qw/a b c/); }); + # or specify list context explicitly + my $thr = threads->create({'context' => 'list'}, + sub { return (qw/a b c/); }); my @results = $thr->join(); - $thread->detach(); + $thr->detach(); - $thread = threads->self(); - $thread = threads->object($tid); + # Get a thread's object + $thr = threads->self(); + $thr = threads->object($tid); + # Get a thread's ID $tid = threads->tid(); - $tid = threads->self->tid(); - $tid = $thread->tid(); + $tid = $thr->tid(); + $tid = "$thr"; + # Give other threads a chance to run threads->yield(); yield(); + # Lists of non-detached threads my @threads = threads->list(); my $thread_count = threads->list(); + my @running = threads->list(threads::running); + my @joinable = threads->list(threads::joinable); + + # Test thread objects if ($thr1 == $thr2) { ... } + # Manage thread stack size $stack_size = threads->get_stack_size(); $old_size = threads->set_stack_size(32*4096); + # Create a thread with a specific context and stack size + my $thr = threads->create({ 'context' => 'list', + 'stack_size' => 32*4096, + 'exit' => 'thread_only' }, + \&foo); + + # Get thread's context + my $wantarray = $thr->wantarray(); + + # Check thread's state + if ($thr->is_running()) { + sleep(1); + } + if ($thr->is_joinable()) { + $thr->join(); + } + + # Send a signal to a thread $thr->kill('SIGUSR1'); + # Exit a thread + threads->exit(); + =head1 DESCRIPTION Perl 5.6 introduced something called interpreter threads. Interpreter threads @@ -160,8 +231,11 @@ for emulating fork() on Windows. The I API is loosely based on the old Thread.pm API. It is very important to note that variables are not shared between threads, all variables -are by default thread local. To use shared variables one must use -L. +are by default thread local. To use shared variables one must also use +L: + + use threads; + use threads::shared; It is also important to note that you must enable threads by doing C as early as possible in the script itself, and that it is not @@ -187,22 +261,6 @@ a code ref. # or my $thr = threads->create(\&func, ...); -The thread may be created in I context, or I context as follows: - - # Create thread in list context - my ($thr) = threads->create(...); - - # Create thread in scalar context - my $thr = threads->create(...); - -This has consequences for the C<-Ejoin()> method describe below. - -Although a thread may be created in I context, to do so you must -I either the C<-Ejoin()> or C<-Edetach()> method to the -C<-Ecreate()> call: - - threads->create(...)->join(); - The C<-Enew()> method is an alias for C<-Ecreate()>. =item $thr->join() @@ -211,31 +269,41 @@ This will wait for the corresponding thread to complete its execution. When the thread finishes, C<-Ejoin()> will return the return value(s) of the entry point function. -The context (void, scalar or list) of the thread creation is also the -context for C<-Ejoin()>. This means that if you intend to return an array -from a thread, you must use Ccreate(...)>, and that -if you intend to return a scalar, you must use C: +The context (void, scalar or list) for the return value(s) for C<-Ejoin()> +is determined at the time of thread creation. - # Create thread in list context + # Create thread in list context (implicit) my ($thr1) = threads->create(sub { my @results = qw(a b c); return (@results); - }; + }); + # or (explicit) + my $thr1 = threads->create({'context' => 'list'}, + sub { + my @results = qw(a b c); + return (@results); + }); # Retrieve list results from thread my @res1 = $thr1->join(); - # Create thread in scalar context + # Create thread in scalar context (implicit) my $thr2 = threads->create(sub { my $result = 42; return ($result); - }; + }); # Retrieve scalar result from thread my $res2 = $thr2->join(); -If the program exits without all other threads having been either joined or -detached, then a warning will be issued. (A program exits either because one -of its threads explicitly calls L, or in the case -of the main thread, reaches the end of the main program file.) + # Create a thread in void context (explicit) + my $thr3 = threads->create({'void' => 1}, + sub { print("Hello, world\n"); }); + # Join the thread in void context (i.e., no return value) + $thr3->join(); + +See L for more details. + +If the program exits without all threads having either been joined or +detached, then a warning will be issued. Calling C<-Ejoin()> or C<-Edetach()> on an already joined thread will cause an error to be thrown. @@ -243,7 +311,11 @@ cause an error to be thrown. =item $thr->detach() Makes the thread unjoinable, and causes any eventual return value to be -discarded. +discarded. When the program exits, any detached threads that are still +running are silently terminated. + +If the program exits without all threads having either been joined or +detached, then a warning will be issued. Calling C<-Ejoin()> or C<-Edetach()> on an already detached thread will cause an error to be thrown. @@ -265,6 +337,17 @@ thread in a program being 0, and incrementing by 1 for every thread created. Class method that allows a thread to obtain its own ID. +=item "$thr" + +If you add the C import option to your C declaration, +then using a threads object in a string or a string context (e.g., as a hash +key) will cause its ID to be used as the value: + + use threads qw(stringify); + + my $thr = threads->create(...); + print("Thread $thr started...\n"); # Prints out: Thread 1 started... + =item threads->object($tid) This will return the I object for the I thread associated @@ -283,8 +366,22 @@ code. =item threads->list() -In a list context, returns a list of all non-joined, non-detached I -objects. In a scalar context, returns a count of the same. +=item threads->list(threads::all) + +=item threads->list(threads::running) + +=item threads->list(threads::joinable) + +With no arguments (or using C) and in a list context, returns a +list of all non-joined, non-detached I objects. In a scalar context, +returns a count of the same. + +With a I argument (using C), returns a list of all +non-joined, non-detached I objects that are still running. + +With a I argument (using C), returns a list of all +non-joined, non-detached I objects that have finished running (i.e., +for which C<-Ejoin()> will not I). =item $thr1->equal($thr2) @@ -305,9 +402,15 @@ to the more natural forms: C creates a thread to execute the block immediately following it. This block is treated as an anonymous subroutine, and so must have a -semi-colon after the closing brace. Like Ccreate()>, C +semicolon after the closing brace. Like Ccreate()>, C returns a I object. +=item $thr->error() + +Threads are executed in an C context. This method will return C +if the thread terminates I. Otherwise, it returns the value of +C<$@> associated with the thread's execution status in its C context. + =item $thr->_handle() This I method returns the memory location of the internal thread @@ -327,6 +430,175 @@ Class method that allows a thread to obtain its own I. =back +=head1 EXITING A THREAD + +The usual method for terminating a thread is to +L from the entry point function with the +appropriate return value(s). + +=over + +=item threads->exit() + +If needed, a thread can be exited at any time by calling +Cexit()>. This will cause the thread to return C in a +scalar context, or the empty list in a list context. + +When called from the I
thread, this behaves the same as C. + +=item threads->exit(status) + +When called from a thread, this behaves like Cexit()> (i.e., the +exit status code is ignored). + +When called from the I
thread, this behaves the same as C. + +=item die() + +Calling C in a thread indicates an abnormal exit for the thread. Any +C<$SIG{__DIE__}> handler in the thread will be called first, and then the +thread will exit with a warning message that will contain any arguments passed +in the C call. + +=item exit(status) + +Calling L inside a thread causes the whole +application to terminate. Because of this, the use of C inside +threaded code, or in modules that might be used in threaded applications, is +strongly discouraged. + +If C really is needed, then consider using the following: + + threads->exit() if threads->can('exit'); # Thread friendly + exit(status); + +=item use threads 'exit' => 'threads_only' + +This globally overrides the default behavior of calling C inside a +thread, and effectively causes such calls to behave the same as +Cexit()>. In other words, with this setting, calling C +causes only the thread to terminate. + +Because of its global effect, this setting should not be used inside modules +or the like. + +The I
thread is unaffected by this setting. + +=item threads->create({'exit' => 'thread_only'}, ...) + +This overrides the default behavior of C inside the newly created +thread only. + +=item $thr->set_thread_exit_only(boolean) + +This can be used to change the I behavior for a thread after +it has been created. With a I argument, C will cause only the +thread to exit. With a I argument, C will terminate the +application. + +The I
thread is unaffected by this call. + +=item threads->set_thread_exit_only(boolean) + +Class method for use inside a thread to change its own behavior for C. + +The I
thread is unaffected by this call. + +=back + +=head1 THREAD STATE + +The following boolean methods are useful in determining the I of a +thread. + +=over + +=item $thr->is_running() + +Returns true if a thread is still running (i.e., if its entry point function +has not yet finished or exited). + +=item $thr->is_joinable() + +Returns true if the thread has finished running, is not detached and has not +yet been joined. In other words, the thread is ready to be joined, and a call +to C<$thr-Ejoin()> will not I. + +=item $thr->is_detached() + +Returns true if the thread has been detached. + +=item threads->is_detached() + +Class method that allows a thread to determine whether or not it is detached. + +=back + +=head1 THREAD CONTEXT + +As with subroutines, the type of value returned from a thread's entry point +function may be determined by the thread's I: list, scalar or void. +The thread's context is determined at thread creation. This is necessary so +that the context is available to the entry point function via +L. The thread may then specify a value of +the appropriate type to be returned from C<-Ejoin()>. + +=head2 Explicit context + +Because thread creation and thread joining may occur in different contexts, it +may be desirable to state the context explicitly to the thread's entry point +function. This may be done by calling C<-Ecreate()> with a hash reference +as the first argument: + + my $thr = threads->create({'context' => 'list'}, \&foo); + ... + my @results = $thr->join(); + +In the above, the threads object is returned to the parent thread in scalar +context, and the thread's entry point function C will be called in list +(array) context such that the parent thread can receive a list (array) from +the C<-Ejoin()> call. (C<'array'> is synonymous with C<'list'>.) + +Similarly, if you need the threads object, but your thread will not be +returning a value (i.e., I context), you would do the following: + + my $thr = threads->create({'context' => 'void'}, \&foo); + ... + $thr->join(); + +The context type may also be used as the I in the hash reference followed +by a I value: + + threads->create({'scalar' => 1}, \&foo); + ... + my ($thr) = threads->list(); + my $result = $thr->join(); + +=head2 Implicit context + +If not explicitly stated, the thread's context is implied from the context +of the C<-Ecreate()> call: + + # Create thread in list context + my ($thr) = threads->create(...); + + # Create thread in scalar context + my $thr = threads->create(...); + + # Create thread in void context + threads->create(...); + +=head2 $thr->wantarray() + +This returns the thread's context in the same manner as +L. + +=head2 threads->wantarray() + +Class method to return the current thread's context. This returns the same +value as running L inside the current +thread's entry point function. + =head1 THREAD STACK SIZE The default per-thread stack size for different platforms varies @@ -339,9 +611,9 @@ By tuning the stack size to more accurately reflect your application's needs, you may significantly reduce your application's memory usage, and increase the number of simultaneously running threads. -N.B., on Windows, Address space allocation granularity is 64 KB, therefore, -setting the stack smaller than that on Win32 Perl will not save any more -memory. +Note that on Windows, address space allocation granularity is 64 KB, +therefore, setting the stack smaller than that on Win32 Perl will not save any +more memory. =over @@ -394,8 +666,10 @@ threaded applications. =item threads->create({'stack_size' => VALUE}, FUNCTION, ARGS) -This change to the thread creation method permits specifying the stack size -for an individual thread. +To specify a particular stack size for any individual thread, call +C<-Ecreate()> with a hash reference as the first argument: + + my $thr = threads->create({'stack_size' => 32*4096}, \&foo, @args); =item $thr2 = $thr1->create(FUNCTION, ARGS) @@ -409,7 +683,7 @@ existing thread (C<$thr1>). This is shorthand for the following: =head1 THREAD SIGNALLING -When safe signals is in effect (the default behavior - see L +When safe signals is in effect (the default behavior - see L for more details), then signals may be sent and acted upon by individual threads. @@ -433,13 +707,10 @@ expected to act upon. Here's an example for I a thread: use threads; - # Suppress warning message when thread is 'killed' - no warnings 'threads'; - sub thr_func { # Thread 'cancellation' signal handler - $SIG{'KILL'} = sub { die("Thread killed\n"); }; + $SIG{'KILL'} = sub { threads->exit(); }; ... } @@ -473,7 +744,7 @@ and I capabilities: ... } - # Create a semaphore and send it to a thread + # Create a semaphore and pass it to a thread my $sema = Thread::Semaphore->new(); my $thr = threads->create('thr_func', $sema); @@ -503,16 +774,19 @@ current operation has completed. For instance, if the thread is I on an I/O call, sending it a signal will not cause the I/O call to be interrupted such that the signal is acted up immediately. +Sending a signal to a terminated thread is ignored. + =head1 WARNINGS =over 4 -=item A thread exited while # other threads were still running +=item Perl exited with active threads: -A thread (not necessarily the main thread) exited while there were still other -threads running. Usually, it's a good idea to first collect the return values -of the created threads by joining them, and only then exit from the main -thread. +If the program exits without all threads having either been joined or +detached, then this warning will be issued. + +NOTE: If the I
thread exits, then this warning cannot be suppressed +using C as suggested below. =item Thread creation failed: pthread_create returned # @@ -522,7 +796,8 @@ cause for the failure. =item Thread # terminated abnormally: ... A thread terminated in some manner other than just returning from its entry -point function. For example, the thread may have exited via C. +point function, or by using Cexit()>. For example, the thread +may have terminated because of an error, or by using C. =item Using minimum thread stack size of # @@ -564,10 +839,10 @@ following results in the above error: $thr->set_stack_size($size); -=item Cannot signal other threads without safe signals +=item Cannot signal threads without safe signals Safe signals must be in effect to use the C<-Ekill()> signalling method. -See L for more details. +See L for more details. =item Unrecognized signal name: ... @@ -576,10 +851,71 @@ specified signal being used in a C<-Ekill()> call. =back -=head1 BUGS +=head1 BUGS AND LIMITATIONS + +Before you consider posting a bug report, please consult, and possibly post a +message to the discussion forum to see if what you've encountered is a known +problem. =over +=item Thread-safe modules + +See L when creating modules that may +be used in threaded applications, especially if those modules use non-Perl +data, or XS code. + +=item Using non-thread-safe modules + +Unfortunately, you may encounter Perl modules that are not I. +For example, they may crash the Perl interpreter during execution, or may dump +core on termination. Depending on the module and the requirements of your +application, it may be possible to work around such difficulties. + +If the module will only be used inside a thread, you can try loading the +module from inside the thread entry point function using C (and +C if needed): + + sub thr_func + { + require Unsafe::Module + # Unsafe::Module->import(...); + + .... + } + +If the module is needed inside the I
thread, try modifying your +application so that the module is loaded (again using C and +C<-Eimport()>) after any threads are started, and in such a way that no +other threads are started afterwards. + +If the above does not work, or is not adequate for your application, then file +a bug report on L against the problematic module. + +=item Current working directory + +On all platforms except MSWin32, the setting for the current working directory +is shared among all threads such that changing it in one thread (e.g., using +C) will affect all the threads in the application. + +On MSWin32, each thread maintains its own the current working directory +setting. + +=item Environment variables + +Currently, on all platforms except MSWin32, all I calls (e.g., using +C or back-ticks) made from threads use the environment variable +settings from the I
thread. In other words, changes made to C<%ENV> in +a thread will not be visible in I calls made by that thread. + +To work around this, set environment variables as part of the I call. +For example: + + my $msg = 'hello'; + system("FOO=$msg; echo \$FOO"); # Outputs 'hello' to STDOUT + +On MSWin32, each thread maintains its own set of environment variables. + =item Parent-child threads On some platforms, it might not be possible to destroy I threads while @@ -589,7 +925,7 @@ there are still existing I threads. Creating threads inside C, C or C blocks should not be relied upon. Depending on the Perl version and the application code, results -may range from success, to (apparently harmless) warnings of leaked scalar, +may range from success, to (apparently harmless) warnings of leaked scalar, or all the way up to crashing of the Perl interpreter. =item Unsafe signals @@ -604,7 +940,7 @@ signalling behavior is only in effect in the following situations: =over 4 -=item * Perl was been built with C (see C). +=item * Perl has been built with C (see C). =item * The environment variable C is set to C (see L). @@ -619,20 +955,49 @@ the C<-Ekill()> signalling method cannot be used. Returning closures from threads should not be relied upon. Depending of the Perl version and the application code, results may range from success, to -(apparently harmless) warnings of leaked scalar, all the way up to crashing of -the Perl interpreter. +(apparently harmless) warnings of leaked scalar, or all the way up to crashing +of the Perl interpreter. + +=item Returning objects from threads + +Returning objects from threads does not work. Depending on the classes +involved, you may be able to work around this by returning a serialized +version of the object (e.g., using L or L), and then +reconstituting it in the joining thread. If you're using Perl 5.10.0 or +later, and if the class supports L, +you can pass them via L. + +=item END blocks in threads + +It is possible to add L to threads by using L or +L with the appropriate code. These C blocks +will then be executed when the thread's interpreter is destroyed (i.e., either +during a C<-Ejoin()> call, or at program termination). + +However, calling any L methods in such an C block will most +likely I (e.g., the application may hang, or generate an error) due to +mutexes that are needed to control functionality within the L module. + +For this reason, the use of C blocks in threads is B +discouraged. =item Perl Bugs and the CPAN Version of L -Support for threads extents beyond the code in this module (i.e., -F and F), and into the Perl iterpreter itself. Older +Support for threads extends beyond the code in this module (i.e., +F and F), and into the Perl interpreter itself. Older versions of Perl contain bugs that may manifest themselves despite using the latest version of L from CPAN. There is no workaround for this other -than upgrading to the lastest version of Perl. +than upgrading to the latest version of Perl. -(Before you consider posting a bug report, please consult, and possibly post a -message to the discussion forum to see if what you've encountered is a known -problem.) +Even with the latest version of Perl, it is known that certain constructs +with threads may result in warning messages concerning leaked scalars or +unreferenced scalars. However, such warnings are harmless, and may safely be +ignored. + +You can search for L related bug reports at +L. If needed submit any new bugs, problems, +patches, etc. to: L =back @@ -646,7 +1011,10 @@ L Discussion Forum on CPAN: L Annotated POD for L: -L +L + +Source repository: +L L, L @@ -663,10 +1031,12 @@ L Artur Bergman Esky AT crucially DOT netE -threads is released under the same license as Perl. - CPAN version produced by Jerry D. Hedden +=head1 LICENSE + +threads is released under the same license as Perl. + =head1 ACKNOWLEDGEMENTS Richard Soderberg Eperl AT crystalflame DOT netE -