In this chapter, we look at managing multiple strands of execution within a single application, both with multiple separate processes and with lighter-weight threads. We also cover the related subject of communicating between processes, both within the same application and between applications. In particular, we examine signals and interprocess communication, also known as IPC.
Signals are the operating system's basic mechanism for indicating error conditions and other events asynchronously. We can receive them, for example, as a result of errors in low-level system calls or abnormal termination of socket filehandles. Unless we handle it or state that we wish to ignore it, such a signal will terminate the running application. Ignoring a signal is easy but not always wise, so in this chapter we will see how to write special subroutines called signal handlers to manage signals sensibly. We can also raise signals against other processes, either once in the same application or elsewhere. Not all signals are errors. On Unix platforms, for example, we can use an alarm signal to trigger an event over a period of our choosing.
In the main part of the chapter, we look at writing Perl applications that manage multiple concurrent strands of execution. First we examine creating and handling multiple separate processes. While this is chiefly of interest to Unix programmers, Perl now has quite credible emulation for multiprocessing applications under Windows too. One of the major problems with multiple processes is getting information between them, so we also look at message queues, semaphores, and shared memory, three different solutions to the problem of interprocess communication.
After processes we look at threads, specifically the new interpreter threads introduced with Perl 5.8. While processes exist in relative isolation, with completely separated data and execution environments, threads share everything within the same process. This makes them very lightweight by comparison and easy to share data between. In most languages, it also makes them much trickier to program since it is easy for threads to overwrite the same data. However, interpreter threads enable Perl to keep data used by different threads partitioned away from each other unless we specify that data is to be shared. This greatly simplifies the task of programming threads and making most Perl modules thread-compatible even if they have no special knowledge or understanding of them.
Much like hardware interrupts, signals are exceptional events that happen independently of whatever code a program happens to be executing at the time. They are said to be "out of band," since they also cannot be deferred for handling at a later point in time. Either the program recipient of a thread handles it, or the operating system will handle it by terminating the program.
Typically, the operating environment defines default triggers and behaviors for most signals. A Unix shell, for instance, maps some signals to key sequences, such as KILL
to Ctrl-C, and STOP
to Ctrl-Z. Other processes, as well as the kernel, have the ability to send signals to any designated process.
Every process keeps an index table of each possible signal and its response to each. Whenever a process receives a signal, it stops normal execution and executes the behavior defined for that signal. Depending on the signal, that behavior may be to take some action and then return control back to the interrupted routine. Alternatively, the response might be to do some cleaning up and exit the program or to explicitly ignore the signal.
Perl allows the programmer to redefine the behaviors of most signals in any of these ways as necessary. The signal index is stored in Perl as the hash variable %SIG
, with the key value being the signal name and the value being either
By assigning various values to signals in the hash, we can control how an application responds to different signals. To elaborate a little on what kind of signals we have available, we can dump out a list of them by printing out the keys of the %SIG
hash:
> perl -e "print join q/ /,sort keys %SIG"
At the system level, each signal is denoted as an integer, rather than the name we see here. If we need to cross-reference the numeric and names, we can discover them via kill -l
(provided we're on a Unix platform, of course) or through the position of the name in Perl's Config
variable sig_name
, which is a space-delimited string:
#!/usr/bin/perl
# siglist.pl
use warnings;
use strict;
use Config;
my @signals = split ' ', $Config{sig_name};
for (0..$#signals) {
print "$_ $signals[$_]
" unless $signals[$_] =˜ /^NUM/;
}
This generates a list of all signals and their associated number, skipping over real-time signal numbers beginning NUM
(in the range between RTMIN
and RTMAX
):
0 ZERO
1 HUP
2 INT
3 QUIT
4 ILL
5 TRAP
6 ABRT
7 BUS
8 FPE
9 KILL
10 USR1
...
Many of these signals are obscure, unlikely, or only occur if we have certain features enabled. The signal SIGPWR
, for example, applies to power failure situations and SIGIO
occurs only with filehandles set to asynchronous mode using O_ASYNC
. The most commonly used signals are as listed in Table 21-1 (but note that not all of these signals work on non-Unix platforms).
Table 21-1. Standard Signals and Their Meanings
Name | Key | Meaning |
SIGHUP |
HUP |
Hangup Controlling terminal or process has terminated (for example, a modem, hence "hang up"). Often redefined in daemons to tell them to reread their configuration files and restart operations. |
SIGINT |
INT |
Interrupt Instruct the process to interrupt what it is doing and exit. This signal is trappable (which means we can redefine its handler) so that a process can perform any necessary clean-up before doing so. Pressing Ctrl-C on the keyboard is often the manual way to send this signal. |
SIGQUIT |
QUIT |
Quit A higher priority signal to shut down and, depending on the system's configuration, may produce a core dump. This signal, too, is trappable. |
SIGKILL |
KILL |
Kill An explicit command to tell the process to immediately exit. This signal is not trappable. (Would we really want to take away the kernel's ability to terminate runaway processes?) |
SIGUSR1 |
USR1 |
User-defined signal While this signal is never used by the kernel, the default behavior for any process receiving the signal is to exit. |
SIGUSR2 |
USR2 |
User-defined signal A second signal for process definition. Like USR1 , the default behavior is to exit. |
SIGPIPE |
PIPE |
Broken pipe A pipe that a process was either reading from or writing to has been closed by the other end. |
SIGALRM |
ALRM |
Alarm An alarm timer for this process has expired. Not supported on Microsoft platforms. |
SIGTERM |
TERM |
Terminate Like INT , this instructs the process to exit and is trappable. This signal has a higher priority than INT , but lower than QUIT and KILL . |
SIGCHLD |
CHLD |
Child exit A child process has exited. |
SIGFPE |
FPE |
Floating-point exception The floating-point processor was asked to perform an illegal operation. |
SIGSEGV |
SEGV |
Invalid memory reference An attempt was made to read or write an invalid address in memory. |
SIGCONT |
CONT |
Continue Resume execution if stopped by a STOP signal. |
SIGSTOP |
STOP |
Stop The process is halted until it receives a CONT , at which point it resumes operational. This signal is not trappable. |
SIGIO |
IO |
Asynchronous IO event If a filehandle is set for asynchronous operation ( O_ASYNC ), this signal is raised whenever an event (for example, more input) occurs on it. |
SIGWINCH |
WINCH |
Window changed The window or terminal in which the console of a process is running has changed size (the user resizing a window can do this). Chapter 15 discusses this in more detail. |
For a complete list of signals, there is no substitute for the system documentation (usually man 7 signal
on Unix). Even on Unix, some signals are platform dependent. The same documentation should inform us of the default behavior of each signal. Regardless, by manipulating the contents of the %SIG
hash, we can override these defaults for most signal types and install our own mechanisms for handling signals.
Between Perl 5.6 and 5.8, the way Perl handled signals was overhauled significantly. In the old implementation, a signal could interrupt Perl in the middle of executing an opcode. This made it very tricky to handle signals safely, especially if any significant manipulation of Perl's state happened as a result of the signal. In such cases, the interpreter could find itself in an inconsistent state, with unpredictable consequences.
Perl 5.8 introduces so-called safe signals, which guarantee that signals will only be delivered to the running application in between opcodes. This means that if Perl is busy reading or writing to a filehandle, it will finish the current IO operation before handling the signal. Similarly, if the program is in the middle of a sort operation, the operation will complete first.
The advantage of safe signals is that signal handling is much more robust. The disadvantage is that since some operations can take a long time, receipt of a signal may not occur quickly. For the most part, this is not an issue, but in a few applications, it might be more important to handle a signal quickly than try to keep Perl happy (typically this would be situations where the program is always going to terminate as a result of the signal and never attempt to resume). For these applications, we can set the environment variable PERL_SIGNALS
to unsafe
:
> PERL_SIGNALS=unsafe immediatesignalapp.pl
To explicitly request safe signals, we can set the variable to safe
instead. Prior to Perl 5.8, this variable has no effect (and signals are always "unsafe").
A string or subroutine reference may be set as values of the %SIG
hash to control what happens when a given signal is received:
Value | Action |
DEFAULT or undef |
Perform the default behavior as determined by the system. |
IGNORE |
Instruct the process to take no action in response to the signal. Untrappable signals are unaffected by this setting (such as KILL ). |
&subreference |
If a subroutine reference or an anonymous subroutine is set as the value of a signal, then it is called whenever that signal is received. We can then decide how to handle it ourselves, including ignoring it, raising a different signal, dying, and so on. |
subroutine |
If the name of the subroutine is set as a string, this will be evaluated as &main::subroutine when the signal is received. |
For example, to ignore SIGPIPE
signals, we would put the following:
$SIG{PIPE} = 'IGNORE';
To restore the default handling for SIGINT
signals:
$SIG{INT} = 'DEFAULT';
To find out the current setting of SIGALRM
(remembering that undef
is equal to DEFAULT
):
$alarming = $SIG{ALRM};
To set a subroutine as a signal handler:
$SIG{USR1} = &usr1handler;
The last of these is, of course, the most interesting. Signal handlers, when called, receive the name of the signal that called them as an argument, so we can assign multiple signals to the same handler or handle each signal individually.
$SIG{HUP} = &handler;
$SIG{STOP} = &handler;
$SIG{USR1} = &handler;
If we set a text string that is not DEFAULT
or IGNORE
, then it is taken as a symbolic reference to a subroutine in the main (not the current) package. So be careful about spelling. Thus
$SIG{INT} = 'DEFLAT';
actually means
$SIG{INT} = &main::DEFLAT;
This will silently fail unless we are using the -w
flag with Perl, in which case it will merely complain on STDERR
that the handler DEFLAT
is undefined. Although this is a perfectly legal way to set a signal handler, the fact that it defaults to the main package can cause confusion when handling signals inside packages—even if the package defines a subroutine with the same name, it won't get called. Note also that though this is a form of symbolic reference, it is not trapped by the use strict refs
pragma. Conversely, if we try to set a signal that does not exist, Perl will complain with an error, for example:
No such signal SIGFLARE at...
A practical example for redefining trappable signals would be when our program creates temporary files. A well-behaved program should clean up after itself before exiting, even when unexpectedly interrupted. In the following example, we will redefine the INT
handler to remove a temporary PID
file before exiting. This will keep the program from leaving PID
files around when the user interrupts the program with a Ctrl-C:
$SIG{INT} = sub {
warn "received SIGINT, removing PID file and exiting.
";
unlink "$ENV{HOME}/.program.pid";
exit 0;
};
The die and warn Pseudo-Handlers
In addition to the standard signals, the %SIG
hash also allows us to set handlers for Perl's error reporting system, specifically the warn
and die
functions together with derivatives of them like carp
and croak
(supplied by the Carp
module). These are not true signal handlers but hooks into Perl's internals, which allow us to react to events occurring within Perl. The %SIG
hash makes a convenient interface because, aside from some minor differences in behavior, they operate very similarly to signals.
Neither the warn
or die
hooks are present as keys in the %SIG
hash by default—we have to add them:
$SIG{__WARN__} = &watchout;
$SIG{__DIE__} = &lastwillandtestament;
Both handlers may customize the error or warning before passing it on to a real warn
or die
(the action of the handler is suppressed within the handler itself, so calling warn
or die
a second time will do the real thing). A warning handler may choose to suppress the warning entirely; die handlers, however, cannot avert death, but only do a few things on its deathbed, so to speak. See Chapter 16 for more on die
and warn
, and registering handlers for them.
The hook mechanism is not extensible; the __
prefix and suffix merely distinguish these special handlers from true signal handlers. They do not, however, allow us to create arbitrary signals and handlers.
Writing Signal Handlers
Signal handlers are just subroutines. When they are called, Perl passes them a single parameter: the name of the signal. For example, here is a program containing a very simple signal handler that raises a warning whenever it receives an INT
signal, but otherwise does nothing with it:
#!/usr/bin/perl
# inthandler1.pl
use warnings;
use strict;
sub handler {
my $sig = shift;
print "Caught SIG$sig!
";
}
# register handler for SIGINT
$SIG{INT} = &handler;
# kill time
while (1) { sleep 1; }
Note that since the handler handled the exception, the program does not exit. If we still want the handler to exit after performing whatever other actions we need done, we must add the exit
command to the end of our handler. Here is another handler that implements this scheme, using a private counter. It will catch the first two signals but defer to the normal behavior on the third reception:
#!/usr/bin/perl
# inthandler2.pl
use warnings;
use strict;
{
# define counter as closure variable
my $interrupted = 0;
sub handler {
foreach ($interrupted) {
$_ == 0 and warn("Once..."), $interrupted++, last;
$_ == 1 and warn("Twice..."), $interrupted++, last;
$_ == 2 and die ("Thrice!");
}
}
}
# register handler for SIGINT
$SIG{INT} = &handler;
# kill time
while (1) { sleep 1; }
A few platforms (BSD systems, typically) cancel signal handlers once they have been called. If we want these systems to be maximally portable, we have to reinstall the handler before we exit it, if we wish it to be called again:
handler {
$sig = shift;
# reinstate handler
$SIG{$sig} = &handler;
... do stuff ...
}
To prevent another signal from coming in before we have redefined it, we will do that first in every handler. Since this does no harm even on platforms that do not need it, it is a good piece of defensive programming if we are worried about portability.
Avoiding Overcomplex Handlers
The preceding handlers are good examples of signal handlers in the sense that they do very little. Signals implicitly herald a critical event, so executing complex code, and especially anything that causes Perl to allocate more memory to store a value, is a bad idea.
Avoiding Memory Allocation
For example, the following signal counting handler is not a good idea; it allocates a new key and value for the hash each time a signal it has not seen previously arrives.
%sigcount;
sub allocatinghandler {
$sigcount {$_[0]}++;
}
This modified version is fine though, as we have guaranteed that all the keys and all the values of the hash already exist, so no new memory needs to be allocated within the handler:
%sigcount = map { $_ => 0 } keys %SIG;
sub nonallocatinghandler {
$sigcount{$_[0]}++;
}
The rule of thumb for any signal handler is to do the absolute minimum necessary.
Uninterruptible Signal Handlers
Unlike the warn
and die
hooks, real signal handlers do not suppress signals while they are running, so if we want to avoid being interrupted a second time while we are still handling a signal, we have to find a way to avoid further signals. One way to do this is simply disable the handler for the duration of the handler:
sub handler {
$SIG{$_[0]} = 'IGNORE';
... do something ...
$SIG{$_[0]} = &handler;
}
A better way is to localize a fresh value for the signal value in $SIG
using local
. This has the same effect as reassigning it explicitly, but with the advantage that the old value is restored immediately on exiting the handler without our intervention:
sub handler {
local $SIG{$_[0]} = 'IGNORE';
... do something...
}
We can suppress signals in normal code using the same principles, for instance, by temporarily reassigning a signal to a new handler or value. We can do that by either making a record of the old one or using local
to suppress it if we happen to be in a section of code that is scoped appropriately:
$oldsig = $SIG{INT};
$SIG{INT} = 'IGNORE';
... code we do not want interrupted ...
$SIG{INT} = $oldsig;
As always, these techniques only work on trappable signals.
Aborting System-Level Operations
On many versions of Unix, as well as a few other platforms, signals that occur during some system calls, and in particular during input and output operations, may cause the operation to restart on the return from the signal handler. Frequently, we would rather abort the whole operation at this point, since resuming is likely to be either pointless or plain wrong. Unfortunately, the only way to abort the interrupted code from inside a signal handler is to use die
or CORE::exit
. Moreover, to be able to resume normal execution at a point of our choice rather than jump into a die
handler or exit the program, we have to put the die
(or rather, the context of the die
) inside an eval
, since that will exit the eval
and resume execution beyond it. So the code we want to abort must all be inside an eval
:
sub handler {
$SIG{$_[0]} = 'DEFAULT';
die;
}
$result = eval {
$SIG{INT} = &handler;
...read from a network connection...
$SIG{INT} = 'DEFAULT';
1; # return true on completion
}
warn "Operation interrupted!
" unless $result;
If the code in the eval
completes successfully, it returns 1
(because that is the last expression in the eval
). If the handler is called, the die
causes the eval
to return undef
. So we can tell if the handler was called or not by the return value from eval
, and therefore we can tell if the code was interrupted. We can vary this theme a little if we want to return an actual result from the eval
; so long as we do not need to validly return a false value, we can always use this technique. Note that even though the die
itself is not in the eval
, the context in which it is called is the eval
's context, so it exits the eval
, not the program as a whole.
This approach also works for setting and canceling alarms to catch system calls that time out; see the later section "Alarms" for more information.
Flexibly Installing Signal Handlers
We have already seen how to install a signal handler by hand; simply set the value of the relevant signal in the signal hash:
$SIG{INT} = &handler;
While fine for a single signal, this is cumbersome for handling many of them. One way to set up multiple signals is to assign a new hash to %SIG
, for example:
%SIG = (%SIG, INT => IGNORE, PIPE => &handler, HUP => &handler);
There is, however, a better way, with the sigtrap
pragmatic module. This takes a list of signal actions and signals, and assigns each signal the action that immediately preceded it. sigtrap
provides two handlers of its own: a stack-trace handler, the default action, and die
, which does what it implies. It also provides several keywords for common groups of signals, as well as a keyword for currently unassigned signals.
The default action is stack-trace
, so the following three pragmas all have the same effect; normal-signals
is the group comprising the SIGINT, SIGHUP, SIGPIPE
, and SIGTERM
signals:
use sigtrap qw(INT HUP PIPE TERM);
use sigtrap qw(stack-trace INT HUP PIPE TERM);
use sigtrap qw(stack-trace normal-signals);
Alternatively, we can choose to set a die
handler. Here are two examples of using die
with the signals that sigtrap
categorizes under error-signals
:
use sigtrap qw(die ABRT BUS EMT FPE ILL QUIT SEGV SYS TRAP);
use sigtrap qw(die error-signals);
We can also supply our own handler, by prefixing it with the keyword handler
:
use sigtrap qw(handler myhandler ALRM HUP INT);
If we want to be sure the handler exists before installing it, we can drop the qw
and use a subroutine reference in a regular list:
use sigtrap handler => &myhandler, qw(ALRM HUP INT);
We may assign different handlers to different signals all at the same time; each signal is assigned the handler before it in the list. The signals at the front are assigned stack-trace
if the first item in the list is not die
or a handler of our own devising:
use sigtrap qw(
stack-trace normal-signals ALRM USR2
die error-signals
handler usrhandler USR1 USR2
die PWR
handler inthandler INT HUP
);
We can specify as many handlers and signals as we like. In addition, later assignments supplant earlier ones, so handler inthandler INT HUP
replaces the assignment to stack-trace
of these signals in the first line (in the guise of normal-signals
). If we want to assign a handler to all signals only if they have not already been assigned or ignored, we can precede the signals we want to trap conditionally with the untrapped
keyword. For example, to call the stack-trace
handler for normal signals not already trapped:
use sigtrap qw(stack-trace untrapped normal-signals);
The opposite of untrapped
is any
; this cancels the conditional assignment of untrapped
:
use sigtrap qw(stack-trace untrapped normal-signals any ALRM USR1 USR2);
If sigtrap
is not passed any signal names at all, it defaults to a standard set that was trapped in previous incarnations of the module. This list is also defined as old-interface-signals
. The following are therefore equivalent:
use sigtrap qw(stack-trace old-interface-signals);
use sigtrap;
The traditional Unix command (and C system call) for sending signals is kill
, a curious piece of nomenclature that comes about from the fact that the default signal sent by the kill
command was 15--SIGTERM
, which caused the program to exit. Despite this, we can send any signal using Perl's kill
function.
The kill
command takes at least two arguments. The first is a signal number or a signal name given as a string. The second and following arguments are the IDs of processes to kill. The return value from kill
is the number of processes to which a signal was delivered (which, since they may ignore the signal, is not necessarily the number of processes that acted on it):
# tell kids to stop hogging the line
kill 'INT', @mychildren;
# a more pointed syntax
kill INT => @mychildren, $grandpatoo;
# commit suicide (die would be simpler)
kill KILL => $$; # $$ is our own process ID
kill (9, $$); # put numerically
# send our parent process a signal
kill USR1 => getppid
Sending a signal to a negative process ID will send it to the process group of that process (including any child processes the process may have, and possibly the parent process that spawned it too, unless the process used setpgrp
). For example, this instruction will send an HUP
signal to every other process in the same process group:
kill HUP => -$$;
The HUP
signal in particular is useful for a parent process to tell all its children to stop what they are doing and reinitialize themselves. The Apache web server does exactly this in forked mode (which is to say, on Unix but not Windows) if we send the main process a HUP
. Of course, the main process does not want to receive its own signal, so we would temporarily disable it:
sub huphandler {
local $SIG{HUP} = 'IGNORE';
kill HUP => -$$;
}
The signal 0
(or ZERO
) is special. It does not actually send a signal to the target process or processes at all but simply checks that those process IDs exist. Since kill
returns the number of processes to which a signal was successfully sent, for signal 0
it reports the number of processes that exist, which makes it a simple way to test if a process is running:
kill(0 => $child) or warn "Child $child is dead!";
Alarms are a particularly useful kind of signal that is issued whenever an internal timer counts down to zero. We can set an alarm with the alarm
function, which takes an integer number of seconds as an argument:
# set an alarm for sixty seconds from now
alarm 60;
If the supplied number is zero, the previous alarm, if any, is canceled:
# cancel alarm
alarm 0;
Setting the alarm will cause the process to exit (as per the default behavior of the signal), unless we also set a new handler for the signal:
alarmhandler {
print "Alarm at ", scalar(localtime), "
";
}
$SIG{ALRM} = &alarmhandler;
Please note that specifying a time interval does not mean that the timer will raise a SIGALRM
in exactly that interval. What it says is that sometime after that interval, depending on the resolution of the system clock and whether our process is in the current context, a signal will be sent.
A Simple Use of Alarms
We can only ever have one alarm
active at a time, per process, so setting a new alarm value resets the timer on the existing alarm, with zero canceling it as noted previously. Here is a program that demonstrates a simple use of alarms, to keep reprompting the user to input a key:
#!/usr/bin/perl
# alarmkey.pl
use strict;
use warnings;
use Term::ReadKey;
# Make read blocking until a key is pressed, and turn on autoflushing (no
# buffered IO)
ReadMode 'cbreak';
$| = 1;
sub alarmhandler {
print "
Hurry up!: ";
alarm 5;
}
$SIG{ALRM} = &alarmhandler;
alarm 5;
print "Hit a key: ";
my $key = ReadKey 0;
print "
You typed '$key'
";
# cancel alarm
alarm 0;
# reset readmode
ReadMode 'restore';
We use the Term::ReadKey
module to give us instant key presses without returns and set $| = 1
to make sure the Hurry up!
prompt appears in a timely manner. In this example, the alarm 0
is redundant because we are about to exit the program anyway, but in a larger application this would be necessary to stop the rest of the program being interrupted by Hurry up!
prompts every five seconds.
Using Alarms to Abort Hung Operations
We can also use alarms to abort an operation that has hung or is taking too long to complete. This works very similarly to the eval
-and-die
example we gave earlier for aborting from a section of code rather than continuing it—this time we use alarms instead to catch an interrupt. Here is a code snippet that aborts from an attempt to gain an exclusive lock over the file associated with the filehandle HANDLE
if the lock is not achieved within one minute:
sub alarmhandler {
die "Operation timed out!";
}
sub interrupthandler {
die "Interrupted!";
}
$SIG{ALRM} = &alarmhandler;
$SIG{INT} = &interrupthandler;
$result = eval {
# set a timer for aborting the lock
alarm 60;
# block waiting for lock
flock HANDLE, LOCK_EX;
# lock achieved! cancel the alarm
alarm 0;
... read/write to HANDLE ...
flock HANDLE, LOCK_UN;
1; # return true on completion
}
warn @_ unless $result;
The alternative approach to this is to turn the lock into a nonblocking lock, then check the return value, sleep for a short while, and then try again. The signal approach is more attractive than this solution in some ways, since it spends less time looping. It is, though, limited by the fact that we can no longer use an alarm for any other reason until we have stopped using the alarm here for this purpose.
Before leaving the subject of signals, some programmers may find it useful to examine the sigaction, sigprocmask, sigpending
, and sigsuspend
functions provided by the POSIX
module. These provide a Perl interface to the standard C library functions of the same name, but with the addition of the POSIX::SigAction
and POSIX::SigSet
object classes to simplify the creation and manipulation of the underlying C language structures. As of Perl 5.8, sigaction
is an atomic operation and can also take an argument of a code reference, DEFAULT
or IGNORE
, just like the %SIG
hash.
In general, there should be no need to use these functions over Perl's built-in signal support (which in any case maps down to them on platforms where they are supported). But for certain cases, such as XSUB programming, the subject of Chapter 20, they might come in useful. See the POSIX manual page for details (the object classes are documented near the end) and the sigaction
manual page on supporting platforms.
Perl supports the creation of new processes through the fork
function, which is an interface to the operating system's underlying fork
function. Forking, a pre-Unix concept, is universal on all Unix-like operating systems. Other platforms like Windows (and pre-OS X Macintosh) use a thread-based model and have no native equivalent of fork
. Instead, Perl provides an emulation of fork
that allows us to "fork" a new process even though the operating system does not understand the concept in those terms. (From Perl 5.8, interpreter threads are used to implement fork
. Since interpreter threads do not automatically share data, they are very good at pretending to be forked processes. That said, if we can guarantee Perl 5.8 or better, we should be able to use threads instead on both platforms anyway.)
The fork
function spawns a clone of itself, creating a child process (the original process is called the main or parent process). The cloning is total, as the child shares the same application code and has its own copies of every variable and filehandle. After the fork, there are two near-identical copies of the original process running, the only immediate difference being the return value from fork
. For the child, it is zero. For the parent, it is the process ID of the child if the fork was successful, or undef
if not. As a result, fork
is always found in close proximity to an if
statement, for example:
if ($pid = fork) {
print "Still in the parent process - we started a child with ",
"process ID $pid
";
} else {
print "This is the child process
";
# terminate child and return success (zero) to the parent
exit 0;
}
What the preceding example does not do, though, is check the return value for a failure of the fork
operation. If the fork
failed entirely, it will return undef
, and we should always check for this possibility (which might occur if the system has reached a limit on processes or does not have enough memory to create the new process). So, we can check it using defined
:
$pid = fork;
die "Failed to fork: $!
" unless defined $pid;
if ($pid) {
# parent
...
} else {
# child
...
}
We can replace the current process with a completely different one by using the exec
function. This replaces the current process in its entirety with the external command supplied as the argument. Even the original process ID is taken over by the new process:
exec 'command', @arguments;
While exec
does have uses in a single-processing application, it is more often used with fork
to run an external command as a subprocess of the original application. We will show some examples of this in action a little later in the chapter.
Code never needs to check the return value from exec
, since if it succeeds the original process will not be there to return a status to in any case. The only time that a program will continue past an exec
is if the exec
fails:
exec @command; # hand over to the next act
die "Exec failed: $!
"; # exec must have failed
Several of Perl's built-in functions perform automatic fork
+execs
. These include the system
and backtick functions and certain variants of open
. We cover all of these later on in the chapter.
The process ID of the current process can always be found from the special variable $$
(also called $PID
or $PROCESS_ID
with the English
module loaded):
print "We are process $$
";
For Unix, a child process can find the process ID of the parent process that created it with the getppid
function (this is not implemented on Windows as it is not meaningful):
$parent = getppid;
print "Our parent is $parent
";
This allows us to use kill
to send a signal to the parent process:
kill "HUP", $parent;
On Windows, there is one caveat to be aware of: handles (the Windows equivalents of Unix PIDs) are unsigned 32-bit integers, while Perl's 32-bit integers are signed. Due to this, handles are occasionally interpreted as a negative integer. This interferes with the semantics of signals, where any signal sent to a negative integer goes to the entire process group, not just a specific process, with rather different results than those desired. Process groups are explained in more detail in the next section.
Whenever a parent process uses fork
(either directly or implicitly) to create a child, the child inherits the process group of the parent. The significance of process groups comes in when signals are sent to a group rather than a single process. If it is intended to be an independent process, then the parent may have its own group ID (which is generally the same as its process ID); otherwise, it will have inherited the process group from its own parent.
We can find the process group of a process by using the getpgrp
function (like getppid
, this is not implemented on Windows or some other non-Unix platforms), which takes a process ID as an argument. To find our own process group, we could write
$pgid = getpgrp $$; #but...
We can also supply any false value, including undef
, to get the process group for the current process. This is generally a better idea because not all versions of the underlying getpgrp
function are the same, and the only value they have in common is 0
. Since Perl maps directly to the underlying function, only 0
is truly portable:
$pgid = getpgrp 0; #...these are better
$pgid = getpgrp;
We usually do not need to find out the process group, since we already know the child will be in the same group as the parent. What we often want to do, however, is change the group to isolate a child from the parent. We can do this with setprgrp
, which takes a process ID and a process group ID as arguments:
setpgrp $pid, $pgid;
In practice, the only process we ever want to change the group for is our own, when we want to divorce a child process from the fate of its parent. Specifically, this insulates the former child from any signals sent to the process group of the parent, so the child will live on even if the parent terminates (and signals its children to do so also). Such child processes are said to be daemons, running independently of the original process that created them.
While in theory we can join any existing group, we generally want to create our own group. Process group IDs are just numbers, and they usually have the same value as the process ID that owns that group. To put ourselves in our own group, therefore, we simply need to give ourselves a process group ID that is equal to our process ID:
setpgrp $$, $$;
Just as before, we can use a false value for both IDs to default to the current process ID, so we can also say
setpgrp 0, 0;
Or even just the following (though not quite as portable):
setpgrp;
Both calls will put the child process into its own group. By doing this, we isolate the child from the process group that the parent originally belonged to. Here is a quick example of a daemon that performs the role of a backseat driver (that is, it keeps shouting out directions when we're trying to concentrate):
#!/usr/bin/perl
# backseat.pl;
use warnings;
use strict;
if (my $pid = fork) {
print "Backseat daemon started with ID $pid
";
sleep 1; # give child time to leave group
kill 9,-$$; # parent suicides gratuitously
}
setpgrp 0, 0;
# child loops in background
while (1) {
alarm 60;
foreach (int rand(3)) {
$_ == 0 and do { print("Go Left!
"); last };
$_ == 1 and do { print("Go Right!
"); last };
$_ == 2 and do { print("Wait, go back!
"); last };
}
sleep rand(3)+1;
}
This is a simplistic example, so there is only one child process. If the parent just exited gracefully, then the child would simply transfer its affections to the init
process (PID 1 on most Unix platforms). However, this parent is badly behaved and kills itself and all its children by sending signal 9 (SIGKILL
) to its process group. The child survives, however, because by the time the parent does this, it has dissociated itself from the group and does not receive the signal. If we comment out the setpgrp
line, the child dies when the parent does and the daemon is not created.
If we do not want to print a friendly message, we can also simplify the fork
statement to just
fork and exit; # isn't self-documenting code great?
When a child exits, the operating system keeps a record of its exit status and retains the child process in the process table. The exit status remains until the parent recovers, or reaps it. If we fail to do this, the dead children turn into zombies when the parent exits (no, really—this is all serious Unix terminology, honest) and hang around the process table, dead but not buried. Using the ps
command on a system where this is happening reveals entries marked zombie
or defunct
.
Perl's built-in functions (other than fork
) automatically deal with this issue for us, so if we create extra processes with open
, we do not have to clean up afterwards. For fork
and the IPC::Open2
and IPC::Open3
modules (both of which we cover later), we have to do our own housekeeping.
To reap an exit status, we use either the basic wait
or more complex waitpid
functions. If we, as the parent process, want to wait for a child to finish before continuing, then there is no problem, we simply use the wait
function to cease execution until the child exits:
# fork a child and execute an external command in it
exec @command unless fork;
# wait for the child to exit
$child_pid = wait;
The process ID of the child is returned by wait
, if we need it, not the exit status. Instead, we find it in $?
.
When wait
returns, it sets the exit code of the child in the special variable $?
. As we covered back in Chapter 16, this is a 16-bit value comprised of two 8-bit values, the exit status in the top half and the signal that caused the child to exit (if any) plus the coredump flag in the bottom half. (This is incidentally identical to the value returned by the Unix wait
system call.) To get the actual exit code and signal number, we therefore need to use
my $exitsig = $? & 127; # signal is lower 7 bits
my $cored = $? & 128; # coredump flag
my $exitcode = $? >> 8; # exit code is upper 8 bits
If we import the appropriate symbols from the POSIX
module, we can also use some convenience functions (with the same names as the macros familiar to C programmers) to extract these values:
use POSIX qw(:sys_wait_h);
$exitsig = WSTOPSIG($?);
$exitcode = WEXITSTATUS($?);
Note The POSIX
module also contains a few other handy functions in the same vein; we list them all briefly at the end of the section.
Only one of the exit codes and the signals will be set, so for a successful exit (that is, an exit code of zero), $?
will be zero too. This is a convenient Boolean value, of course, so we can test $?
for truth to detect a failed process, whether it exited with a non-zero status or aborted by a signal. Of course, since such codes are often left to the discretion of the developer to respect, we cannot always rely on that.
In some cases, particularly if we wrote the external command, the returned code may be an errno
value, which we can assign to $!
for a textual description of the error. In the parent process:
wait;
$exitcode = $? >> 8;
if ($exitcode) {
$! = $exitcode; #assign to $! to 'recreate' error
die "Child aborted with error: $!
";
}
If there are no child processes, then wait
returns immediately with a return value of -1
. However, this is not generally useful since we should not be in the position of calling wait
if we did not fork
first, and if we did attempt to fork
, we should be testing the return value of that operation. If we are handling more than one process, we should use waitpid
instead.
If we have more than one child process, then wait
is not always enough, because it will return when any child process exits. If we want to wait for a particular child, then we need to use waitpid
:
$pid = fork;
if ($pid) {
waitpid $pid, 0;
} else {
...child...
}
Two arguments are taken by waitpid
. The first is the process ID of the child to wait for. The second argument is a flag that effects the operation of waitpid
. The most common flag to place here is WNOHANG
, which tells waitpid
not to wait if the child is still running but return immediately with -1
. This argument is one of several constants defined by the POSIX
module, and we can import it either from the :sys_wait_h
group or directly:
use POSIX qw(:sys_wait_h);
Or:
use POSIX qw(WNOHANG);
We can use this to periodically check for a child's exit without being forced to wait for it:
$pid = fork;
if ($pid) {
while (waitpid $pid, WNOHANG) == −1) {
print "Waiting for $pid...
";
sleep 5;
}
} else {
...child...
}
This works for a single child process, but if we have several children to tidy up after, we have to collect all their process IDs into a list and check all of them. This is not convenient. Fortunately, we can pass -1
to waitpid
to make it behave like wait
and return with the value of the first available dead child:
# wait until any child exits
waitpid −1, 0;
# this is the nonblocking version
waitpid −1, WNOHANG;
We do not necessarily want to keep checking for our children exiting, particularly if their exit status is irrelevant and we only want to remove them from the process table. What we need is a way to call waitpid
when the child exits without having to check periodically in a loop. Fortunately, we can install a signal handler for the SIGCHLD
signal that allows us to do exactly this. However, since more than one child could exit at once, calling waitpid
only once may not be enough. An efficient signal handler thus needs to keep calling waitpid
until there are no exit codes left to collect, yielding a design like this:
sub waitforchildren {
my $pid;
do {
$pid = waitpid -1, WNOHANG;
} until ($pid! == −1);
}
$SIG{CHLD} = &waitforchildren;
This is tedious, but necessary if we are to manage child processes responsibly and portably. On some systems we can get away with simply ignoring SIGCHLD
and have the operating system remove dead children for us:
$SIG{CHLD} = 'IGNORE';
Or, if we can let the child change its process group, we can let init reap
children instead. This is not portable across all systems, though, so in general the preceding solutions are preferred.
Note For the technically curious, Perl maps the built-in waitpid
to an appropriate native function, waitpid
or possibly wait4
. Which is chosen depends on the platform.
The POSIX
module defines several symbols and functions other than WNOHANG
for use with the wait
and waitpid
system calls. We import all of them when we import with the :sys_wait_h
tag:
use POSIX qw(:sys_wait_h);
There are actually two flags. One is WNOHANG
, which we have already seen. The other, WUNTRACED
, also returns process IDs for children that are currently stopped (that is, have been sent a SIGSTOP
) and have not yet been resumed. For example:
$possibly_stopped_pid = waitpid -1, WNOHANG | WUNTRACED;
In addition, the convenience functions listed in Table 21-2 are defined.
Table 21-2. Convenience Functions
Communicating between different processes, or interprocess communication (IPC), is a subject with many facets. Perl provides many possible ways to establish communications between processes, from simple unidirectional pipes, through bidirectional socket pairs, to fully fledged control over an externally executed command.
In this section, we are going to discuss the various ways in which different processes can communicate with one another and the drawbacks of each approach while paying particular attention to communications with an externally run command. The open
function provides a simple and easy way to do this, but it can also be a dangerous one if we do not do some thorough screening. Instead we can turn to the fork
ing version of open
or use the IPC::Open2
or IPC::Open3
library modules for a safer approach.
Before covering the more advanced ways to establish communications between processes and external programs, we will cover the obvious and simple methods like system
and do
. They may not be sophisticated, but sometimes they are all we need to get the job done.
If we simply want to run an external program, we do not necessarily have to adopt measures like pipes (covered in the next section) or child processes; we can just use the system
function:
system "command plus @arguments";
However, if system
is passed a single argument, it checks it to see if it contains shell-special characters (like spaces, or quotes), and if present, starts a shell as a subprocess to run the command. This can be dangerous if the details of the command are supplied by the user; we can end up executing arbitrary commands like rmdir
. A better approach is to pass the arguments individually, and this causes Perl to execute the command directly, bypassing the shell:
system 'command', 'plus', @arguments;
However, system
only returns the exit code of the command, which is great if we want to know if it succeeded or not but useless for retrieving its output. For that, we can use the backtick operator qx
or the equivalent backtick quotes:
# these two statements are identical. Note both interpolate too.
$output = `command plus @arguments`;
$output = qx/command plus @arguments/;
Unfortunately, both variants of the backtick operator create a shell, and this time there is no way to avoid it, since there is no way to pass a list of arguments. If we really want to avoid the shell, we have to start getting creative using a combination of open, pipe
, and fork
. Fortunately, Perl makes this a little simpler for us, as we will see shortly.
Not to be overlooked, we can also execute external programs with do
if they are written in Perl. This function is essentially an enhanced version of eval
that reads its input from an external file rather than having it written directly into the code. Its intended purpose is for loading in library files (other than modules, for which use
or require
are preferred), which do not generate output. If the script happens to print things to standard output, that will work too, so long as we don't want to control the output.
$return_value = do './local_script.pl';
The do
command has a lot of disadvantages, however. Unlike eval
, it does not cache the code executed for later use, and it is strictly limited in what it can do. For more useful and constructive forms of interprocess communication, we need to involve pipes.
A pipe is, simply put, a pair of file handles joined together. In Perl, we can create pipes with the pipe
function, which takes two filehandle names as arguments. One filehandle is read-only, and the other is write-only. By default, Perl attempts to buffer IO
. This is also the case when we want a command to respond to each line without waiting for a series of lines to come through to flush the buffer. So we would write
pipe (READ, WRITE);
select WRITE;
$| = 1;
use IO::Handle;
pipe (READ, WRITE);
WRITE->autoflush(1);
We can also create pipes with the IO::Pipe
module. This creates a "raw" IO::Pipe
object that we convert into a read-only or write-only IO::Handle
by calling either the reader
or writer
method:
use IO::Pipe;
my $pipe = new IO::Pipe;
if (fork) {
$pipe->reader;
# $pipe is now a read-only IO::Handle
} else {
$pipe->writer;
# $pipe is now a write-only IO::Handle
}
The most common use for pipes is for IPC (interprocess communication, mentioned earlier), which is why we bring them up here rather than in Chapter 12. As a quick example and also as an illustration of pipes from the filehandle perspective, here is a program that passes a message back and forth between a parent and child process using two pipes and a call to fork
:
#!/usr/bin/perl
# message.pl
use warnings;
use strict;
pipe CREAD, PWRITE; # parent->child
pipe PREAD, CWRITE; # child->parent
my $message = "S";
if (fork) {
# parent--close child end of pipes
close CREAD;
close CWRITE;
syswrite PWRITE, "$message
";
while (<PREAD>) {
chomp;
print "Parent got $_
";
syswrite PWRITE, "P$_
";
sleep 1;
}
} else {
# child--close parent end of pipes
close PREAD;
close PWRITE;
while (<CREAD>) {
chomp;
print "Child got $_
";
syswrite CWRITE, "C$_
";
}
}
As this example shows, both processes have access to the filehandles of the pipes after the fork
. Each process closes the two filehandles that it does not need and reads and writes from the other two. In order to ensure that buffering does not deadlock the processes waiting for each other's message, we use the system-level syswrite
function to do the actual writing, which also absolves us of the need to set the autoflush
flag. When run, the output of this program looks like this:
Child got : S
Parent got: CS
Child got : PCS
Parent got: CPCS
Child got : PCPCS
Parent got: CPCPCS
...
Note that this program works because each process reads exactly one line of input and produces exactly one line of output, so they balance each other. A real application where one side or the other needs to read arbitrary quantities of data will have to spend more time worrying about deadlocks; it is all too easy to have both processes waiting for input from the other.
If the first or last character of a file name passed to open is a pipe (|
) symbol, the remainder of the file name is taken to be an external command. A unidirectional pipe connects the external process to our program. Input to or output from the external process is connected to our process based on the position of the pipe symbol. If the symbol precedes the command, the program's input (STDIN
) is connected to an output statement in our process. If the symbol appends the command, the program's output (STDOUT
) is accessed with an input type statement from our process.
If the pipe character occurs at the start of the file name, then the input to the external command is connected to the output of the filehandle, so printing to the filehandle will send data to the input of the command. For example, here is a standard way of sending an e-mail on a Unix system by running the sendmail
program and writing the content of the e-mail to it through the pipe:
# get e-mail details from somewhere, e.g., HTML form via CGI.pm
my ($from_addr, $to_addr, $subject, $mail_body, $from_sig) = get_email();
# open connection to 'sendmail' and print e-mail to it
open (MAIL, '|/usr/bin/sendmail -oi -t') || die "Eep! $!
";
print MAIL <<END_OF_MAIL;
From: $from_addr;
To: $to_addr
Subject: $subject
$mail_body
$from_sig
END_OF_MAIL
# close connection to sendmail
close MAIL;
If, on the other hand, the pipe character occurs at the end, then the output of the external command is connected to the input of the filehandle. Reading from the filehandle will receive anything that the external command prints. For example, here is another Unix-based example of using an open
to receive the results of a ps
(list processes) command:
#!/usr/bin/perl
# pid1.pl
use warnings;
use strict;
my $pid = open (PS,"ps aux|") || die "Couldn't execute 'ps': $!
";
print "Subprocess ID is: $pid
";
while (<PS>) {
chomp;
print "PS: $_
";
}
close PS;
The return value of open
when it is used to start an external process this way is the process ID of the executed command. We can use this value with functions such as waitpid
, which we covered earlier in the chapter.
Note that it is not possible to open an external program for both reading and writing this way, since the pipe is unidirectional. Attempting to pass a pipe in at both ends will only result in the external command's output being chained to nothing, which is unlikely to be what we want. One solution to this is to have the external command write to a temporary file and then read the temporary file to see what happened:
if (open SORT, "|sort > /tmp/output$$") {
... print results line by line to SORT ...
close SORT;
open(RESULT, '/tmp/output$$')
... read sorted results ...
close RESULT;
unlink '/tmp/output$$';
}
Another, better, solution is to use the IPC::Open2
or IPC::Open3
module, which allows both read and write access to an external program. The IPC::
modules are also covered in this chapter, under the section "Bidirectional Pipes to External Processes."
Standard pipes on Unix are only one-way, but we can create a pair of filehandles that look like just a pipe, but one that can flow in both directions. Perl provides a number of functions to create and manage sockets, which are bidirectional networking endpoints represented in our applications as filehandles. They can be used to communicate between different processes and different systems across a network, and a large part of Chapter 22 is concerned with them. Here, however, we are interested in their use for local interprocess communications.
The socketpair
function stands apart from the other socket functions because it does not have any application in networking applications. Instead, it creates two sockets connected back to back, with the output of each connected to the input of the other. The result is what looks and feels like a bidirectional pipe. (Unfortunately, Windows programmers are out of luck here—the concept is not valid on these platforms.)
Sockets have domains, types, and protocols associated with them. The domain in Perl can be either the Internet or Unix, the type a streaming socket, datagram socket, or raw socket, and the protocol can be something like PF_INET
or PF_UNIX
(these constants actually stand for Protocol Families). This is the general form of socketpair
being used to create a parent and child filehandle:
socketpair PARENT, CHILD, $domain, $type, $protocol;
However, most of this is fairly irrelevant to socketpair
; its sockets do not talk to network interfaces or the file system, they do not need to listen for connections, they cannot be bound to addresses, and finally they are not bothered about protocols, since they have no lower-level protocol API to satisfy. Consequently, we generally use a Unix domain socket, since they are more lightweight than an Internet domain socket. We make it streaming so we can use it like an ordinary filehandle, and not bother with the protocol at all. The actual use of socketpair
is thus almost always
use Socket;
socketpair PARENT, CHILD, AF_UNIX, SOCK_STREAM, PF_UNSPEC;
Here is a version of the message passing program we showed earlier using a pair of sockets rather than two pairs of pipe handles:
#!/usr/bin/perl
# socketpair.pl
use warnings;
use strict;
use Socket;
socketpair PARENT, CHILD, AF_Unix, SOCK_STREAM, PF_UNSPEC;
my $message = "S";
if (fork) {
syswrite PARENT, "$message
";
while (<PARENT>) {
chomp;
print "Parent got: $_
";
syswrite PARENT, "P$_
";
sleep 1;
}
} else {
while (<CHILD>) {
chomp;
print "Child got : $_
";
syswrite CHILD, "C$_
";
}
}
In fact, we could also close the parent and child socket handles in the child and parent processes respectively, since we do not need them—we only needed one end of each pipe. We can also use the socket in only one direction by using the shutdown
function to close either the input or the output:
shutdown CHILD, 1; # make child read-only
shutdown PARENT, 0; # make parent write-only
The difference between close
and shutdown
is that close
only affects the filehandle itself; the underlying socket is not affected unless the filehandle just closed was the only one pointing to it. In other words, shutdown
includes the socket itself, and hence all filehandles associated with it are affected.
This program is a lot more advanced in the way that it manufactures the conduit between the two processes, because it uses Perl's socket support to create the filehandles, but the benefit is that it makes the application simpler to write and generates fewer redundant filehandles.
One problem with using open
to start an external process is that if the external command contains spaces or other such characters that are significant to a shell, open
will run a shell as a subprocess and pass on the command for it to interpret, so that any special characters can be correctly parsed. The problem with this is that it is potentially insecure if the program is to be run by untrusted users, and it will fail if taint mode is enabled through the -T
option, as, for example, is the case with a CGI script. Functions such as exec
and system
allow us to separate the parameters of a command into separate scalar values and supply them as a list, avoiding the shell.
Unfortunately, open
does not directly allow us to pass in a command as a list. Instead it allows us to use exec
to actually run the command by supplying it with the magic file names |-
or -|
. This causes open
to create a pipe and then fork to create a child process. The child's standard input or standard output (depending on whether |-
or -|
was used) is connected to the filehandle opened in the parent. If we then use exec
to replace the child process with the external command, the standard input or output is inherited, connecting the external process directly to the filehandle created by open
in the parent.
The return value from open
in these cases is the process ID of the child process (in the parent) and zero (in the child), the same as the return value from fork
, enabling us to tell which process we are now running as.
Of course, it is not obligatory to run an external command at this point, but this is by far the most common reason for using a forked open. It is also by far the most common reason for using exec
, which replaces the current process by the supplied command. Since exec
allows the command to be split up into a list (that is, a list containing the command and arguments as separate elements), we can avoid the shell that open
would create if we used it directly (or handed it a scalar string with the complete command and arguments in it). Here's an example of running the Unix ps
command via a forked open:
#!/usr/bin/perl
# pid2.pl
use warnings;
use strict;
my $pid = open (PS, "-|");
die "Couldn't fork: $!
" unless defined $pid;
if ($pid) {
print "Subprocess ID is: $pid
";
while (<PS>) {
chomp;
print "PS: $_
";
}
close PS;
} else {
exec qw[ps -ef]; # no shells here
}
Or, more tersely and without recording the process ID:
#!/usr/bin/perl
# pid3.pl
use warnings;
use strict;
open (PS, "-|") || exec 'ps', '-ef';
while (<PS>) {
chomp;
print "PS: $_
";
}
close PS;
Perl provides a pair of modules, IPC::Open2
and IPC::Open3
, that provide access to bidirectional pipes. These modules have the added advantage that the subroutines they supply, open2
and open3
, permit the external commands to be given as a list, again avoiding an external shell.
As we know from Chapter 12, all applications get three filehandles for free when they start and are represented by STDIN, STDOUT
, and STDERR
. These are the three filehandles all applications use, and they are also the three filehandles with which we can talk and listen to any external process. This is what the piped open
does, but only for one of the filehandles. However, due to the facts that STDIN
is read-only and STDOUT
and STDERR
are write-only, we can in theory create pipes for each of them, since we only need a unidirectional conduit for each handle. This is what the open2
and open3
subroutines provided by IPC::Open2
and IPC::Open3
do. The difference between them is that open2
creates pipes for standard input and output, whereas open3
deals with standard error too.
Using either module is very simple. In the old style of Perl IO programming, we supply typeglobs (or typeglob references) for the filehandles to associate with the external command, followed by the command itself:
use IPC::Open2;
my $pid = open2(*RD, *WR, @command_and_arguments);
Or:
use IPC::Open3;
my $pid = open3(*WR, *RD, *ERR, @command_and_arguments);
Confusingly, the input and output filehandles of open2
are in a different order in open3
. This is a great source for errors, so check carefully, or only use open3
to avoid getting them the wrong way around.
Since typeglobs are considered somewhat quaint these days, we can also pass in IO::Handle
objects for much the same effect:
use IPC::Open2;
use IO::Handle;
my $in = new IO::Handle;
my $out = new IO::Handle;
my $pid = open2($in, $out, 'command', 'arg1', 'arg2'),
print $out "Hello there
";
my $reply = n;
In a similar vein but without the explicit calls to IO::Handle
's new
method, we can have open2
or open3
create and return the filehandles for us if we pass in a scalar variable with an undefined value:
use IPC::Open3;
my ($in,$out,$error);
my $pid = open3($out, $in, $error, 'command', 'arg1', 'arg2'),
print $out "Hello there
";
my $reply = n;
Both open2
and open3
perform a fork
-and-exec
behind the scenes, in the same way that a forked open
does. The return value is the process ID of the child that actually executed (with exec
) the external command. In the event that establishing the pipes to the external command fails, both subroutines raise a SIGPIPE
signal, which we must catch or ignore (this we have covered earlier on in the chapter). Neither subroutine is concerned with the well being of the actual external command, however, so if the child aborts or exits normally, we need to check for ourselves and clean up with waitpid
:
use POSIX qw(WNOHANG);
my $pid = open2($in, $out, 'command', @arguments);
until (waitpid $pid, WNOHANG) {
# do other stuff, and/or read/writes to $in & $out
}
Note that this particular scheme assumes we are using nonblocking reads and writes; otherwise, the waitpid
may not get called. We can also check for a deceased external process by detecting the EOF
condition on the input or error filehandles (or by returning nothing from a sysread
), but we still need to use waitpid
to clean up the child process.
If we do not want to do anything else in the meantime, perhaps because we have another child process busy doing things elsewhere, we can simply say
# wait for child process to finish
waitpid $pid, 0;
If the write filehandle is prefixed with >&
, then the external command is connected directly to the supplied filehandle, so input that arrives on it is sent directly to the external command. The filehandle is also closed in our own process. Similarly, if <&
is given to the read or error filehandles, they are connected directly to the application. Here's a script that illustrates this in action:
# Usage: myscript.pl 'somecommand @args'
use IPC::Open3;
print "Now entering $ARGV[0]
";
my $pid = open3('>&STDIN', '<&STDOUT', '<&STDERR', @ARGV);
waitpid $pid, 0;
print "$ARGV[0] finished.
";
Note that we use standard input for the writing handle and standard output for the reading handle. That's because this script is a middleman in the transaction; input comes in from standard input but then goes out to the external command, and vice versa for standard output.
With a little embellishment, this script could be made useful, for example, logging uses of various commands, checking arguments, or processing tainted data.
We do not have to redirect all three filehandles, only the ones we don't want to deal with:
sub open2likeopen3 {
return open3(shift, shift, '>&STDERR', @_);
}
This implements a subroutine functionally identical to open2
(unless we already have redirected standard error, that is) but with the arguments in the same order as open3
.
Handling Bidirectional Communications
Some external commands will communicate with us on a line-by-line basis. That is, whenever we send them something, we can expect at least one line in response. In these cases, we can alternate between writing and reading as we did with our pipe
and socketpair
examples earlier. Commands like ftp
are a good example of this kind of application.
However, many commands can accept arbitrary input and will not send any output until they have received all of the input. The only way to tell such a command that it has all the input it needs is to close the filehandle, so we often need to do something like this:
@instructions = <ARGV>;
($in, $out);
# send input and close filehandle
$pid = open2($in, $out, 'command', @arguments);
print $out @instructions;
close $out;
# receive result
@result = n;
close $in;
# clean up and use the result
waitpid $pid, 0;
print "Got:
@result";
If we want to carry out an ongoing dialog with an external process, then an alternating write
-read
-write
process is not always the best way to approach the problem. In order to avoid deadlocks, we have to continually divert attention from one filehandle to the other. Adding standard error just makes things worse.
Fortunately, there are two simple solutions, depending on whether we can (or want to) fork or not. First, we can use the select
function or the vastly more convenient IO::Select
module to poll multiple input filehandles, including both the normal and error output of the external command plus our own standard input. Alternatively, we can fork child processes to handle each filehandle individually. We can even use threads, if we have a version of Perl that is built to use them. We go into more detail on threads later on.
The problem with forked processes, as we have observed before and will observe again when we get to threads, is that they do not share data easily. Consequently, to communicate with each other or share resources, processes need to either establish a channel for communication or find some common point of reference that can be seen by all the processes concerned.
In this section, we are going to discuss the IPC facilities provided by Unix systems and their near cousins, generically known as System V IPC, after the variant of Unix in which it first appeared. There are three components to System V IPC: message queues, semaphores, and shared memory segments. System V IPC is now a fairly venerable part of Unix and is not generally portable to non-Unix platforms that do not comply with POSIX. Some parts of it are also implemented through pipes and socket pairs for ease of implementation. It still has its uses, though, in particular because the objects that we can create and access with it are persistent in memory and can survive the death of the applications that use them. This allows an application to store all its mission-critical data in shared memory and to pick up exactly where it left off if it is terminated and restarted.
Like most parts of Perl that interface to a lower-level library, IPC requires a number of constants that define the various parameters required by its functions. For IPC, these constants are defined by the IPC::SysV
module, so almost any application using IPC includes the statement
use IPC::SysV;
Note that we do not actually have to be on a System V Unix platform to use IPC, but we do have to be on a platform that has the required IPC support. In general, Perl will not even have the modules installed if IPC is not available, and we will have to find alternative means to our goal, some of which are illustrated during the course of the other sections in this chapter. Even on Unix systems IPC is not always present. If it is, we can usually find out by executing this command:
> ipcs
If IPC is available, this will produce a report of all currently existing shared memory segments, semaphores, and message queues, usually in that order.
The common theme between IPC message queues, semaphores, and shared memory segments is that they all reside persistently in memory and can be accessed by any process that knows the resource ID and has access privileges. This differentiates them from most other IPC strategies, which establish private lines of communication between processes that are not so easily accessed by other unrelated processes.
Strictly speaking, Perl's support for IPC is available in the language as the function calls msgctl, msgget, msgrcv, msgsnd, semctl, semget, semop, shmctl, shmget, shmread
, and shmwrite
. These are merely wrappers for the equivalent C calls, and hence are pretty low level, though very well documented. However, since these functions are not very easy to use, the IPC::
family of modules includes support for object-oriented IPC access. In the interests of brevity, we will concentrate on these modules only in the following sections.
The IPC::SysV
module imports all of the specified SysV
constants for use in our programs in conjunction with the other IPC
modules. Table 21-3 presents a summary of the most widely used constants. To see the full set of what IPC::SysV
can export, we can do a perldoc -m
on the module and consult development man pages for further information. Error constants are imported with the core module Errno
.
Table 21-3. Widely Used SysV Constants
At one time, message queues were the only effective way to communicate between processes. They provide a simple queue that processes may write messages into at one end and read out at the other. We can create two kinds of queues, private and public. Here is an example of creating a private queue:
use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRWXU);
use IPC::Msg;
my $queue = new IPC::Msg IPC_PRIVATE, S_IRWXU | IPC_CREAT;
The new
constructor takes two arguments. The first is the queue's identifier, which for a private queue is IPC_PRIVATE
. The second is the permissions of the queue, combined with IPC_CREAT
if we wish to actually create the queue. Like files, queues have a mask for user, group, and other permissions. This allows us to create a queue that we can write to, but applications running under other user IDs can only read from.
For a private queue, full user permissions are the most obvious, and we specify these with S_IRWXU
. This is defined by the Fcntl
module, but IPC::SysV
imports the symbols for us, so we don't have to use Fcntl
ourselves. We could also have said 0700
using octal notation. (Permissions are discussed in detail in Chapter 13.)
If the queue is private, only the process that created the queue and any forked children can access it. Alternatively, if it is public, any process that knows the queue's identifier can access it. For a queue to be useful, therefore, it needs to have a known identifier, or key, by which it can be found. The key is simply an integer, so we can create a public queue, which can be written to by processes running under our user ID (that is, this application) and only read by others with something like the following:
# create a queue for writing
my $queue = new IPC::Msg 10023, 0722 | IPC_CREAT;
Another process can now access this message queue with
my $queue = new IPC::Msg 10023, 0200;
On return, $queue
will be a valid message object for the queue, or undef
if it did not exist. Assuming success, we can now read and write the queue to establish communications between the processes. If we had created a private queue (not specifying the SysV ID
key) and we want to send the message queue's key to another process so we can establish communications, we can extract it with id
:
my $queue = new IPC::Msg IPC_PRIVATE, 0722 | IPC_CREAT;
my $id = $queue->id;
To send a message, we use the snd
method:
$queue->snd($type, $message, $flags);
The message is simply the data we want to send. The type is a positive integer, which can be used by the rcv
method to select different messages based on their type. The flags argument is optional, but it can be set to IPC_NOWAIT
to have the method return if the message could not be sent immediately (in this case, $!
will be set to EAGAIN
). It is possible for error code constants to be imported by the module.
To receive a message, we use the rcv
method:
my $message;
$queue->rcv($message, $length, $type, $flags);
The first argument must be a scalar variable into which the message is read. The second defines the maximum length of the message to be received. If the message is larger than this length, then rcv
returns undef
and sets $!
to E2BIG
. The type allows us to control which message we receive and is an integer with the following possible meanings:
Integer Value | Meaning |
0 |
Read the first message on the queue, regardless of type. |
> 0 |
Read the first message on the queue of the specified type. For example, if the type is 2 , then only messages of type 2 will be read. If none are available, this will cause the process to block until one is. However, see IPC_NOWAIT and MSG_EXCEPT later. |
< 0 |
Read the lowest and furthest forward message on the queue with a type equal to or less than the absolute value of the specified type. For example, if the type is -2 , then the first message with type 0 will be returned; if no messages of type 0 are present, the first message of type 1 , or if no messages of type 1 are present, the first message of type 2 is returned. |
The flags may be one or more of the following:
Flag | Action |
MSG_EXCEPT |
Invert the sense of the type so that for zero or positive values it retrieves the first message not of the specified type. For instance, a type of 1 causes rcv to return the first message not of type 1 . |
MSG_NOERROR |
Allow outsize messages to be received by truncating them to the specified length, rather than returning E2BIG as an error. |
IPC_NOWAIT |
Do not wait for a message of the requested type if none are available but return with $! set to EAGAIN . |
Put together, these two functions allow us to set up a multilevel communications queue with differently typed messages for different purposes. The meaning of the type is entirely up to us; we can use it to send different messages to different child processes or threads within our application. Also it can be used as a priority or out-of-band channel marker, to name a few some examples.
The permissions of a queue can be changed with the set
method, which takes a list of key-value pairs as parameters:
$queue->set (
uid => $user_id, # i.e., like 'chmod' for files
gid => $group_id, # i.e., like 'chgrp' for files
mode => $permissions, # an octal value or S_ flags
qbytes => $queue_size # the queue's capacity
)
We can also retrieve an IPC::Msg::stat
object, which we can in turn create, modify, and then update the queue properties via the stat
method:
my $stat = $queue->stat;
$stat->mode(0722);
$queue->set($stat);
The object that the stat
method returns is actually an object based on the Class::Struct
class. It provides the following get/set
methods (the * designates portions of the stat
structure that cannot be directly manipulated):
Method | Purpose |
uid |
The effective UID queue is running with |
gid |
The effective GID queue is running with |
cuid* |
The UID queue was started with |
cgid* |
The GID queue was started with |
mode |
Permissions set on the queue |
qnum* |
Number of messages currently in the queue |
qbytes |
Size of the message queue |
lspid* |
PID of the last process that performed a send on the queue |
lrpid* |
PID of the last process that performed a receive on the queue |
stime* |
Time of the last send call performed on the queue |
rtime* |
Time of the last receive call performed on the queue |
ctime* |
Time of the last change performed on the stat data structure |
Note that changes made to the object returned by the stat
method do not directly update the queue's attributes. For that to happen, we need to either pass the updated stat
object or individual key-value pairs (using the keys listed previously as stat
methods) to the set
method.
Finally, we can destroy a queue, assuming we have execute permission for it, by calling remove
:
$queue->remove;
If we cannot remove the queue, the method returns undef
, with $!
set to indicate the reason, most likely EPERM
. In keeping with good programming practices, it is important that the queue be removed, especially since it persists even after the application exits. However, it is equally important that the correct process do so, and no other process pulls the rug out from under the others.
IPC semaphores are an in-memory set of numeric flags (also known as semaphore sets) that can be read and written by different processes to indicate different states. Like message queues, they can be private or public, having an identifier by which they can be accessed with a permissions mask controlling who can access them.
Semaphores have two uses: first, as a set of shared values, which can be read and written by different processes; and second, to allow processes to block and wait for semaphores to change value, so that the execution of different processes can be stopped and started according to the value of a semaphore controlled by a different process.
The module that implements access to semaphores is IPC::Semaphore
, and we can use it like this:
use IPC::SysV qw(IPC_CREAT IPC_PRIVATE S_IRWXU);
use IPC::Semaphore;
my $size = 4;
my $sem = new IPC::Semaphore(IPC_PRIVATE, $size, IPC_CREAT | S_IRWXU);
This creates a private semaphore set with four semaphores and owner read, write, and execute permissions. To create a public semaphore set, we provide a literal key value instead:
my $sem = new IPC::Semaphore(10023, 4, 0722 | IPC_CREAT);
Other processes can now access the semaphore with
my $sem = new IPC::Semaphore(10023, 4, 0200); # or S_IRDONLY
As with message queues, we can also retrieve the key of the semaphore set with the id
method:
$id = $sem->id;
Once we have access to the semaphore, we can use and manipulate it in various ways, assuming we have permission to do so. A number of methods exist to help us do this, and these are listed here:
Name | Action |
getall |
Return all values as a list. For example:my @semvals = $sem->getall; |
getval |
Return the value of the specified semaphore. For example:# first semaphore is 0, so 4th is 3 |
setall |
Set all semaphore values. For example, to clear all semaphores:$sem->setall( (0) × 4 ); |
setval |
Set the value of the specified semaphore. For example:# set value of 4th semaphore to 1 |
set |
Set the user ID, group ID or permissions of the semaphore, for example:$sem->set( |
Alternatively we can get, manipulate, and set a stat
object as returned by the stat
method in the same manner as IPC::Msg
objects.
The real power of semaphores is bound up in the op
method, which performs one or more semaphore operations on a semaphore set. This is the mechanism by which processes can block and be unblocked by other processes.
Each operation consists of three values: the semaphore number to operate on, an operation to perform, and a flag value. The operation is actually a value to increment or decrement by, and it follows these rules:
getzcnt
.getncnt
.We can choose to operate as many semaphores as we like. All operations must be able to complete before the operation as a whole can succeed. For example:
$sem->op(
0, −1, 0, # decrement semaphore 1
1, −1, 0, # decrement semaphore 2
3, 0, 0, # semaphore 3 must be zero
);
The rules for blocking on semaphores allow us to create applications that can cooperate with each other; one application can control the execution of another by setting semaphore values. Applications can also coordinate over access to shared resources. This a potentially large subject, so we will just give an simple illustrative example of how a semaphore can coordinate access to a common shared resource:
1
, and creates a shared resource, for example, a file or an IPC shared memory segment. However, it decides to do a lot of initialization, and so it doesn't access the resource immediately.0
, and accesses the shared resource.0
, so it cannot access it and therefore blocks.1
, and so the operation succeeds and no longer blocks.And so on . . .
Although this sounds complex, in reality it is very simple. In code, each application simply accesses the semaphore, creating it if not present, then adds two lines around all accesses to the resource to be protected:
sub access_resource {
# decrement semaphore, blocking if it is already zero
$sem->op(0, −1, 0);
... access resource ...
# increment semaphore, allowing access by other processes
$sem->op(0, 1, 0);
}
If we have more than one resource to control, we just create a semaphore set with more semaphores.
The basis of this approach is that the applications agree to cooperate through the semaphore. Each one has the key for the semaphore (because it is given in a configuration file, for instance), and it becomes the sole basis for contact between them. Even though the resource being controlled has no direct connection to the semaphore, each application always honors it before accessing it. The semaphore becomes a gatekeeper, allowing only one application access at a time.
If we do not want to block while waiting for a semaphore, we can specify IPC_NOWAIT
for the flag value. We can do this on a "per semaphore basis" too, if we want, though this could be confusing. For example:
sub access_resource {
return undef unless $sem->op(0, −1, IPC_NOWAIT);
... access resource ...
$sem->op(0, 1, 0);
}
We can also set the flag SEM_UNDO
(if we import it from IPC::SysV
first). This causes a semaphore operation to be automatically undone if the process exits, either deliberately or due to an error. This is helpful in preventing applications that abort while locking a resource and then never releasing it again. For example:
$sem->op(0, −1, IPC_NOWAIT | SEM_UNDO);
die unless critical_subroutine();
As with message queues, care must be given to not leave unused segments around after the last process exits.
We will return to the subject of semaphores when we come to talk about threads, which have their own semaphore mechanism, inspired greatly by the original IPC implementation described previously.
While message queues and semaphores are relatively low-level constructs made a little more accessible by the IPC::Msg
and IPC::Semaphore
modules, shared memory has altogether more powerful support module in the form of IPC::Shareable
. The key reason for this is that IPC::Shareable
implements shared memory through a tie
mechanism, so rather than reading and writing from a memory block, we can simply attach a variable to it and use that.
The tie
takes four arguments, a variable (which may be a scalar, an array, or a hash), IPC::Shareable
for the binding, and then an access key, followed optionally by a hash reference containing one or more key-value pairs. For example, the following code creates and ties a hash variable to a shared memory segment:
use IPC::Shareable;
our %local_hash;
tie %local_hash, 'IPC::Shareable', 'key', {create => 1}
$local_hash{hashkey} = 'value';
This creates a persistent shared memory object containing a hash variable that can be accessed by any application or process by tie
-ing a hash variable to the access key for the shared memory segment (in this case key
):
# in a process in an application far, far away...
%other_hash;
tie %other_hash, IPC::Shareable => 'key';
$value = $other_hash{hashkey};
A key feature of shared memory is that, like memory queues and semaphores, the shared memory segment exists independently of the application that created it. Even if all the users of the shared memory exit, it will continue to exist so long as it is not explicitly deleted (we can alter this behavior, though, as we will see in a moment).
Note that the key value is actually implemented as an integer, the same as semaphores and message queues, so the string we pass is converted into an integer value by packing the first four characters into a 32-bit integer value. This means that only the first four characters of the key are used. As a simple example, baby
and babyface
are the same key to IPC::Shareable
.
The tied variable can be of any type, including a scalar containing a reference, in which case whatever the reference points to gets converted into a shared form. This includes nested data structures and objects, making shared memory ties potentially very powerful. However, each reference becomes a new shared memory object, so a complex structure can quickly exceed the system limit on shared memory segments. In practice, we should only try to tie relatively small nested structures to avoid trouble.
The fourth argument can contain a number of different configuration options that determine how the shared memory segment is accessed, as listed in Table 21-4.
Table 21-4. IPC::Shareable Configuration Options
Other than the destroy
option, we can remove a shared memory segment by calling one of three methods implemented for the IPC::Shareable
object that implements the tie (which may be returned by the tied
function), as shown in Table 21-5.
Table 21-5. IPC::Shareable Methods
Method | Purpose |
remove |
Remove the shared memory segment, if we have permission to do so. |
clean_up |
Remove all shared memory segments created by this process. |
clean_up_all |
Remove all shared memory segments in existence for which this process has permissions to do so. For example: # grab a handle to the tied object via the 'tied' |
We can also lock variables using the IPC::Shareable
object's shlock
and shunlock
methods. If the variable is already locked, the process attempting the lock will block until it becomes free. For example:
$shmem->lock;
$shared_scalar = "new value";
$shmem->unlock;
Behind the scenes this lock is implemented with IPC::Semaphore
, so for a more flexible mechanism, use IPC::Semaphore
objects directly.
As a lightweight alternative to IPC::Shareable
, we can make use of the IPC::ShareLite
module, naturally available from CPAN. This provides a simple store-fetch mechanism using object methods and does not provide a tied interface. However, it is faster than IPC::Shareable
.
Threads are, very loosely speaking, the low fat and lean version of forked processes. Like processes, each thread is a separate strand of execution. Also like processes, newly created threads are owned by the parent thread that created them. They also have unique identifiers, though these are thread IDs rather than process IDs. We can even wait for a thread to finish and collect its exit result, just like waitpid
does for child processes.
However, threads run within the same process and share the same interpreter, code, and data. Nothing is duplicated except the thread of execution. This makes them much more lightweight, so we can have very many of them, and we don't need to use any of the workarounds that forked processes need.
Thread support for Unix platforms is still considered experimental, but as of Perl 5.8 it is increasingly robust. Windows versions of Perl are implicitly capable of threads, and in fact fork
is implemented with threads on that platform—the process ID returned by fork
is actually a thread ID. With a few caveats, there is no reason we cannot now write threaded Perl applications, so long as we built Perl with thread support initially, of course.
To find out if threads are available programmatically, we can check for the usethreads
key in the %Config
hash:
BEGIN {
use Config;
die "Threadbare!
" unless $Config{usethreads};
}
This tells us threads are supported, but not which kind. If we need to check that we have interpreter threads rather than the older 5.005 threads, we can also (or instead) check for useithreads
:
BEGIN {
use Config;
die "No interpreter threads!
" unless $Config{useithreads};
}
From the command line, we can check if threads are present by trying to read the documentation. The Thread
module is present for both types of thread. The threads
module will only be present if interpreter thread support is enabled:
> perldoc threads
The threads
module is the basis of handling threads in Perl. It is an object-oriented module that represents threads as objects, which we can create using new
and manipulate with methods. In addition, it provides a number of functions that operate on a per-thread basis. The older Thread
module exists even with interpreter threads as a portability aid for programs written to the old interface. However, since data is automatically shared in the older implementation and automatically kept private with interpreter threads, this gesture is unlikely to work for threaded programs of any complexity.
Thread modules come in two flavors, pragmatic and application oriented. Basic support for threads is supplied by the pragmatic threads
and threads::shared
modules, the latter of which provides the ability to share data between threads. These two modules interface directly into the interpreter's thread mechanics and are necessary to enable threads and shared data in our application. Although they are pragmatic, both modules also provide methods and subroutines for stating, stopping, querying, and manipulating threads.
Application-oriented thread modules live in the Thread::
namespace. The Thread::Semaphore
and Thread::Queue
modules, which both come standard with Perl (and which are covered later in the chapter) are two good examples, but there are plenty more interesting examples on CPAN for the curious.
Threads resemble forked processes in many ways, but in terms of creation they resemble, and indeed are, subroutines. The standard way of creating a thread, the create
method, takes a subroutine reference and a list of arguments to pass to it. The subroutine is then executed by a new thread of execution, while the parent thread receives a thread object as the return value. The following code snippet illustrates how it works:
use threads;
sub threadsub {
my $self = threads->self;
...
}
my $thread = threads->create(&threadsub, @args);
The new
method is an alias, so we can also say
my $thread = new threads(&threadsub, @args);
This creates a new thread, with threadsub
as its entry point, while the main thread continues on. The alternative way to create a thread is with the async
function, whose syntax is analogous to an anonymous subroutine. This function is not imported by default, so we must name it in the import list to the Thread
module:
my $thread = async {
my $self = threads->self;
...
};
Just like an anonymous subroutine, we end the async
statement with a semicolon. The block may not need it, but the statement does.
The choice of create/new
or async
depends on the nature of the thread we want to start; the two approaches are identical in all respects apart from their syntax. If we only want to start one instance of a thread, then async
should be used. Otherwise, create
or new
is better if we want to use the same subroutine for many different threads:
my $thread1 = new threads &threadsub, $arg1;
my $thread2 = new threads &threadsub, $arg2;
my $thread3 = new threads &threadsub, $arg3;
or, with a loop:
# start a new thread for each argument passed in @ARGV:
@threads;
foreach (@ARGV) {
push @threads, threads->create(&threadsub, $_);
}
Because interpreter threads make a copy of the data in the original thread to create the new thread, we do not normally need to take any special action to create new threads, and code that is not thread-aware is automatically thread-safe. However, if we have any non-Perl data in a thread, Perl cannot deal with it directly—this particularly affects extension modules with XSUBs—and we may have a problem. To solve it, we can make use of the special CLONE
method in any package that needs to deal with special cases:
package Special::Thread::Module;
sub CLONE {
# handle any special thread cloning needs for this package
}
If present, this method is called—in every loaded package that defines or inherits it—just after the thread is created and just before its entry point is called. We can also use this method to adjust or "thin down" data that we do not need to have cloned to conserve memory.
Since we can start up many different threads all with the same subroutine as their entry point, it might seem tricky to tell them apart. However, this is not so.
First, we can pass in different arguments when we start each thread to set them on different tasks. An example of this would be a filehandle, newly created by a server application, and this is exactly what the example of a threaded server in Chapter 22 does. Second, a thread can create a thread object to represent itself using the self
class method:
my $self = threads->self;
With this thread object, the thread can now call methods on itself, for example tid
, which returns the underlying thread number:
my $self_id = $self->tid;
or all in one statement:
my $self_id = threads->self->tid;
It is possible to have more than one thread object containing the same thread ID, and this is actually common in some circumstances. We can check for equivalence by comparing the IDs, but we can do better by using the equals
method:
print "Equal!
" if $self->equal($thread);
or, equivalently:
print "Equal!
" if $thread->equal($self);
Thread identities are useful for many purposes, one of the most useful being thread-specific data.
There is one major difference between the older implementation of threads provided in Perl 5.6 and earlier and the interpreter threads available in Perl 5.8 onward: data is automatically shared in the older model, and never shared, unless we ask for it, in the newer one. The older model mirrors the behavior of the underlying thread support provided by the operating system, but there is no reason for Perl to mimic this behavior in its own threads, so instead the interpreter tracks the use of data by threads and duplicates unshared data as needed. This is actually more convenient, at least for code that was not written with threads in mind, since it means that by default threads can never inadvertently interfere with each other by overwriting each other's data.
To actually share data, we make use of the threads::shared
module, which provides the share
function to mark a variable as shared across all threads. In actuality, this simply switches off the smart duplication of data that the interpreter would ordinarily carry out, for indicated variables only. If the threads module has not been loaded previously, share
and other functions like lock
and cond_wait
that are also provided by this module are exported as nonfunctional stubs. This means our code will still run in a nonthreaded context, but it also means we must make sure to load threads first:
use threads;
use threads::shared;
Once a variable is shared, each thread will see the same underlying storage when the variable is accessed, rather than getting its own copy:
my $answer = 42;
share($answer);
my @array = (1,2,3);
share(@array);
If we know in advance which variables we want to share, which is generally the case, we can use the shared
attribute instead:
my $answer : shared = 42;
my @array : shared = qw(1 2 3);
my %hash : shared = (one => 1, two => 2, three => 3);
We are not limited to sharing declared variables. We can also create a new anonymous reference and share it all in one go. However, since the subroutine normally expects a variable argument, we must call it with &
to suppress the prototype:
my $aref = &share([1 2 3]);
Either way, once a variable is shared, all threads have access to the same data. In order to prevent them from overwriting each other and coordinate access to the shared data, we now need to apply a lock so that only one thread can access it at any given moment.
Variable Locks
When multiple threads share data, we sometimes have problems stopping them from treading on each other's toes. Since data is not shared between threads by default, we can largely ignore this problem for code that does not choose to share data, but the problem still exists when sharing common resources among a pool of threads.
The lock
subroutine does handle this, however. It takes any variable as an argument and places a lock on it so that no other thread may lock it for as long as the lock persists, which is defined by its lexical scope. The distinction between lock and access is important; any thread can simply access the variable by not bothering to acquire the lock, so the lock is only good if all threads abide by it. Just like flock
for filehandles, a thread variable lock is advisory, not compelled.
It is not necessarily given that because data is shared it needs to be locked. Any number of threads can read the same data without risk of conflict, after all. It is important to place a lock on the data for code that writes or modifies it, but it is not always necessary to place a lock for code that only reads it. If we write our code so that only one thread can ever update the shared data, we may not need a lock at all.
If we have three shared variables, all of which are involved in any transaction, we can lock just one of them to control access to all three or invent a new lock variable solely for the purpose—it does not matter what approach we use, so long as we do it consistently.
As a short and incomplete example, this subroutine locks a filehandle used for output, so that only one thread can write to the filehandle at a time:
my $sharedfh : shared = IO::File->open("> app.log");
sub writelog {
lock $sharedfh;
print $sharedfh, @_;
}
The shared and locked properties of a variable are distinct from its value, so it does not matter what (or when) we assign to the variable, or even whether we assign to it at all.
It is not necessary to explicitly unlock the variable, and in fact not possible either. The lock is released as soon as it goes out of scope, which in this case is at the end of the subroutine. Any lexical scope is acceptable, however, so we can also place locks inside the clauses of if
statements, loops, map
and grep
blocks, and eval
statements. We can also choose to lock arrays, hashes, or globs:
lock @array;
lock %hash;
lock *glob;
Alternatively, we can lock just an element, which gives us a form of record-based locking, if we define a record as an array element or hash value:
my %ghash : shared;
sub varlocksub {
my $key = shift;
lock $ghash{$key};
...
}
In this version, only one element of the hash is locked, so any other thread can enter the subroutine with a different key and the corresponding value at the same time. If a thread comes in with the same key, however, it will find the value under lock and key (so to speak) and will have to wait.
While it is possible and perfectly legal to place a lock on a hash or array, locking a hash does not imply a lock on any of its keys, and locking an array does not imply locking any of its elements. Similarly, locking a key or element does not imply a lock on the hash or array to which it belongs.
Subroutine Locks
In Perl 5.6, the locked
and method
attributes provided serialized access to a subroutine. Neither of these attributes exist for interpreter threads, and we can no longer lock a subroutine by reference, either. But we can lock a variable associated with the subroutine, for example, the code reference of an anonymous subroutine:
my $subref : shared = sub {
lock $subref;
print "This is thread ",threads->self->tid,"
";
}
This is just syntactic sugar: it doesn't really matter what the variable is, so long as we relate it somehow to the subroutine to lock. We can equally use a closure, like in this example:
#!/usr/bin/perl -w
# locksub.pl
use strict;
use warnings;
use threads;
use threads::shared;
{ my $lock : shared;
sub mysub {
print "Thread ",threads->self->tid()," waiting for access
";
lock $lock;
print "I am thread ",threads->self->tid(),"
";
sleep 1;
threads->detach();
}
}
foreach (1..5) {
threads->create(&mysub);
}
do {
sleep 1;
print "Waiting for threads:",(map { " ".$_->tid } threads->list),"
";
} while (threads->list);
The closure hides the lock variable where external code cannot get to it. Here each thread tries to execute the mysub
subroutine, but only one thread can hold the lock on the closure variable $lock
at any given time, and so access to the subroutine is serialized. Each thread sleeps for a second and then detaches itself to let the main thread know it is done. Meanwhile, the main thread waits for all the child threads to detach before exiting. This is a simplistic thread management scenario, of course—semaphores and queues are more sophisticated techniques we will look at in a moment.
It is not usually necessary to lock object methods this way because object instances are generally created on a per-thread basis and are not shared between threads—if we need to coordinate method access to other shared variables, then we would lock on those variables in any case. There are currently limitations on the sharing of blessed object references, so it is often inadvisable to share them in any case—see the threads::shared
manual page for details. (In our IO::File
example earlier, we were safe because the lock works even if the blessed nature of the glob reference is lost between threads—no IO::File
methods got called.)
Perl keeps a list of every thread that has been created. We can get a copy of this list, as thread objects, with the threads->list
class method:
@threads = threads->list;
One of these threads is our own thread. We can find out which by using the equal
method:
$self = threads->self;
foreach (@threads) {
next if $self->equal($_);
...
}
Just because a thread is present does not mean that it is running, however. Perl keeps a record of the return value of every thread when it exits and a record of the thread for as long as that value remains unclaimed. This is similar to child processes that have not had waitpid
called for them. The threaded equivalent of waitpid
is the join
method, which we call on the thread we want to retrieve the exit value for:
my $return_result = $thread->join;
The join
method will block until the thread on which join
was called exits. If the thread aborted (for example by calling die
), then the error will be propagated to the thread that called join
. This means that it will itself die unless the join
is protected by an eval
:
my $return_result = eval { $thread->join; }
if ($@) {
warn "Thread unraveled before completion
";
}
As a convenience for this common construct, the Thread
module also provides an eval
method, which wraps join
inside an eval
for us:
my $return_result = $thread->eval;
if ($@) {
warn "Thread unraveled before completion
";
}
It is bad form to ignore the return value of a thread, since it clutters up the thread list with dead threads. If we do not care about the return value, then we can tell the thread that we do not want it to linger and preserve its return value by telling it to detach:
$thread->detach;
This is the thread equivalent of putting a child process in its own process group—the parent no longer gets the exit status when the child exits. The catch is that if the thread dies, nobody will notice, unless a signal handler for the __DIE__
hook has been registered and it checks threads->self
for the dying thread. If we join a moribund thread from the main thread without precautions, we do have to worry about the application dying as a whole.
As a slightly fuller and more complete (although admittedly not particularly useful) example, this short program starts up five threads, then joins each of them in turn before exiting:
#!/usr/bin/perl
# join.pl
use warnings;
use strict;
# check we have threads
BEGIN {
use Config;
die "No interpreter threads!
" unless $Config{useithreads};
}
use threads;
# define a subroutine for threads to execute
sub threadsub {
my $self = threads->self;
print "Thread ", $self->tid, " started
";
sleep 10;
print "Thread ", $self->tid, " ending
";
}
# start up five threads, one second intervals
my @threads;
foreach (1..5) {
push @threads, new threads &threadsub;
sleep 1;
}
# wait for the last thread started to end
while (my $thread = shift @threads) {
print "Waiting for thread ", $thread -> tid, " to end...
";
$thread->join;
print "Ended
";
}
# exit
print "All threads done
";
Typically, we care about the return value, and hence would always check them. However, in this case we are simply using join
to avoid terminating the main thread prematurely.
Locked variables have more applications than simply controlling access. We can also use them as conditional blocks by having threads wait on a variable until it is signaled to proceed. In this mode the variable, termed a condition variable, takes on the role of a starting line; each thread lines up on the block (so to speak) until the starting pistol is fired by another thread. Depending on the type of signal we send, either a single thread is given the go-ahead to continue, or all threads are signaled.
Condition variables are a powerful tool for organizing threads, allowing us to control the flow of data through a threaded application and preventing threads from accessing shared data in an unsynchronized manner. They are also the basis for other kinds of thread interaction. We can use thread semaphores, provided by the Thread::Semaphore
module, to signal between threads. We can also implement a queue of tasks between threads using the Thread::Queue
module. Both these modules build upon the basic features of condition variables to provide their functionality but wrap them in a more convenient form.
To get a feel for how each of these work, we will implement a basic but functional threaded application, first using condition variables directly, then using semaphores, and finally using a queue.
Condition Variables
Continuing the analogy of the starting line, to "line up" threads on a locked variable we use the cond_wait
subroutine. This takes a locked variable as an argument, unlocks it, and then waits until it receives a signal from another thread. When it receives a signal, the thread resumes execution and relocks the variable.
To have several threads all waiting on the same variable, we need only have each thread lock
and then cond_wait
the variable in turn. Since the lock
prevents more than one thread executing cond_wait
at the same time, the process is automatically handled for us. The following code extract shows the basic technique applied to a pool of threads:
my $lockvar; # lock variable - note it is not locked at this point
sub my_waiting_thread {
# wait for signal
{
lock $lockvar;
cond_wait $lockvar;
}
# ...the rest of the thread, where the work is done
}
for (1..10) {
threads->create(&my_waiting_thread);
}
This code snippet shows ten threads, all of which use the same subroutine as their entry point. Each one locks and then waits on the variable $lockvar
until it receives a signal. Since we don't want to retain the lock on the variable after we leave cond_wait
, we place both lock
and cond_wait
inside their own block to limit the scope of the lock. This is important since other threads cannot enter the waiting state while we have a lock on the variable; sometimes that is what we want, but more often it isn't.
Having established a pool of waiting threads, we need to send a signal to wake one of them up, which we do with cond_signal
:
# wake up one thread
cond_signal $lockvar;
This will unlock one thread waiting on the condition variable. The thread that is restarted is essentially random; we cannot assume that the first thread to block will be the first to be unlocked again. This is appropriate when we have a pool of threads at our disposal, all of which perform the same basic function. Alternatively, we can unlock all threads at once by calling cond_broadcast
thusly:
# everybody up!
cond_broadcast $lockvar;
This sends a message to each thread waiting on that variable, which is appropriate for circumstances where a common resource is conditionally available and we want to stop or start all threads, depending on whether they are available or not. It is important to realize, however, that if no threads are waiting on the variable, the signal is discarded; it is not kept until a thread is ready to respond to it. It is also important to realize that this has nothing (directly) to do with process signals, as handled by the %SIG
array; writing a threaded application to handle process signals is a more complex task (see the Thread::Signal
module for details).
Note that the actual value of the lock variable is entirely irrelevant to this process, so we can use it for other things. For instance, we can use it to pass a value to the thread at the moment that we signal it. The following short threaded application does just this, using a pool of service threads to handle lines of input passed to them by the main thread. While examining it, pay close attention to the two condition variables that lay at the heart of the application:
$pool
: Used by the main thread to signal that a new line is ready. It is waited on by all the service threads. Its value is programmed to hold the number of threads currently waiting, so the main thread knows whether or not it can send a signal or if it must wait for a service thread to become ready.$line
: Used by whichever thread is woken by the signal to $pool
. Lets the main thread know that the line of input read by the main thread has been copied to the service thread and that a new line may now be read. The value is the text of the line that was read.The two condition variables allow the main thread and the pool of service threads to cooperate with each other. This ensures that each line read by the main thread is passed to one service thread both quickly and safely:
#!/usr/bin/perl
# threadpool.pl
use warnings;
use strict;
use threads;
use threads::shared;
my $threads = 3; # number of service threads to create
my $line : shared= "";
# parent lock variable and input line set to "" here, we
# assign each new line of input to it, and set it to 'undef'
# when we are finished to tell service threads to quit
my $pool : shared = 0;
# child lock variable and pool counter set to 0 here,
# service threads increment it when they are ready for input
# a locked print subroutine--stops thread output mingling
{
my $lock : shared;
sub thr_print {
lock $lock;
print @_;
}
}
# create a pool of three service threads
foreach (1..$threads) {
threads->create(&process_thing);
}
# main loop: Read a line, wait for a service thread to become available,
# signal that a new line is ready, then wait for whichever thread picked
# up the line to signal to continue
while ($line = <>) {
chomp $line;
thr_print "Main thread got '$line'
";
# do not signal until at least one thread is ready
if ($pool==0) {
thr_print "Main thread has no service threads available, yielding
";
threads->yield until $pool>0;
}
thr_print "Main thread has $pool service threads available
";
# signal that a new line is ready
{
lock $pool;
cond_signal $pool;
}
thr_print "Main thread sent signal, waiting to be signaled
";
# wait for whichever thread wakes up to signal us
{
lock $line;
cond_wait $line;
}
thr_print "Main thread received signal, reading next line
";
}
thr_print "All lines processed, sending end signal
";
# set the line to special value 'undef' to indicate end of input
$line = undef;
{
lock $pool;
# tell all threads to pick up this 'line' so they all quit
cond_broadcast $pool;
}
thr_print "Main thread ended
";
exit 0;
# the thread subroutine--block on lock variable until work arrives
sub process_thing {
my $self=threads->self;
my $thread_line;
thr_print "Thread ",$self->tid," started
";
while (1) {
# has the 'quit' signal been sent while we were busy?
last unless (defined $line);
# wait to be woken up
thr_print "Thread ",$self->tid," waiting
";
{
lock $pool;
$pool++;
cond_wait $pool; #all threads wait here for signal
$pool--;
}
# retrieve value to process
thr_print "Thread ",$self->tid," signaled
";
$thread_line = $line;
# was this the 'quit' signal? Check the value sent
last unless (defined $thread_line);
# let main thread know we have got the value
thr_print "Thread ",$self->tid," retrieved data, signaling main
";
{
lock $line;
cond_signal $line;
}
# do private spurious things to it
chomp ($thread_line=uc($thread_line));
thr_print "Thread ",$self->tid," got '$thread_line'
";
}
thr_print "Thread ",$self->tid," ended
";
}
Once the basic idea of a condition variable is understood, the way in which this application works becomes clearer. However, there are a few aspects still worth pointing out. In particular, the $pool
variable is used by the main thread to ensure that it only sends a signal when there is a service thread waiting to receive it. To achieve this, we increment $pool
immediately before cond_wait
and decrement it immediately afterwards. By doing this, we ensure that $pool
accurately reflects the number of waiting service threads; if it is zero, the main thread uses yield
to pass on execution until a service thread becomes available again.
The means by which the application terminates is also worth noting. Threads do not necessarily terminate just because the main thread does, so in order to exit a threaded application cleanly, we need to make sure all the service threads terminate, too. This is especially important if resources needed by some threads are being used by others. In this application, the main thread uses cond_signal
to signal the $pool
variable and wake up one service thread when a new line is available. Once all input has been read, we need to shut down all the service threads, which means getting their entire attention. To do that, we give $line
the special value undef
and then use cond_broadcast
to signal all threads to pick up the new "line" and exit when they see that it is undef
. However, this alone is not enough because a thread might be busy and not waiting. To deal with that possibility, the service thread subroutine also checks the value of $line
at the top of the loop, just in case the thread missed the signal.
Finally, this application also illustrates the use of the locked subroutine attribute. The thr_print
subroutine is a wrapper for the regular print
function that only allows one thread to print at a time. This prevents the output of different threads from getting intermingled. For simple tasks like this one, locked subroutines are an acceptable solution to an otherwise tricky problem that would require at least a lock variable. For longer tasks, locked subroutines can be a serious bottleneck, affecting the performance of a threaded application, so we should use them with care and never for anything likely to take appreciable time.
As of Perl 5.8.3, cond_wait
can take two shared variable arguments; the first is the signal variable, the second the lock variable:
cond_wait $sigvar,$lockvar;
It works identically to the one-argument form, except for the division of responsibility. The objective is to allow us to signal the same variable several times and unlock more than one thread concurrently, by having different threads use different lock variables for the same signal variable. The number of different lock variables in play is equal to the total number of concurrent threads the signal variable can trigger.
Also from Perl 5.8.3 onwards, the threads
module also provides the cond_timedwait
function. It works identically to its untimed counterpart earlier, but it takes an additional timeout value in seconds. The return value of cond_timedwait
is true if a signal was received and false if the timeout was reached first. This lets us write code that can periodically stop waiting to do other tasks:
{
lock $line;
while (! cond_timedwait($line,10)) {
thr_print "Yawn...
";
}
}
As with cond_wait
, we can split the signal and lock variables if we wish:
cond_timedwait $sigvar,$lockvar,$timeout;
This works identically to the two-argument form, except for the division of responsibility. As with cond_wait
, this form of the function allows us to signal the same variable several times and unlock more than one thread concurrently.
Semaphores
Although it works perfectly well, the preceding application is a little more complex than it needs to be. Most forms of threads whatever language or platform they reside on support the concept of semaphores, and Perl is no different. We covered IPC semaphores earlier, and thread semaphores are very similar. They are essentially numeric flags that take a value of zero or any positive number and obey the following simple rules:
Perl provides thread semaphores through the Thread::Semaphore
module, which implements semaphores in terms of condition variables—the code of Thread::Semaphore
is actually quite short as well as instructive. It provides one class method, new
, and two object methods, up
and down
. new
creates a new semaphore:
$semaphore = new Thread::Semaphore; # create semaphore, initial value 1
$semaphore2 = new Thread::Semaphore(0) # create semaphore, initial value 0
$semaphore->up; # increment semaphore by 1
$semaphore->up(5); # increment semaphore by 5
Finally, down
decrements a semaphore, blocking if necessary:
$semaphore->down; # decrement semaphore by 1
$semaphore->down(5); # decrement semaphore by 5
Depending on our requirements, we can use semaphores as binary stop/go toggles or allow them to range to larger values to indicate the availability of a resource. Here is an adapted form of our earlier threaded application, rewritten to replace the condition variables with semaphores:
#!/usr/bin/perl
# semaphore.pl
use warnings;
use strict;
use threads;
use Thread::Semaphore;
my $threads = 3; # number of service threads to create
my $line : shared = ""; # input line
my $main = new Thread::Semaphore; # proceed semaphore, initial value 1
my $next = new Thread::Semaphore(0); # new line semaphore, initial value 0
# a locked print subroutine--stops thread output mingling
{ my $lock : shared;
sub thr_print {
lock $lock;
print @_;
}
}
# create a pool of three service threads
foreach (1..$threads) {
threads->create(&process_thing);
}
# main loop: read a line, raise 'next' semaphore to indicate a line is
# available, then wait for whichever thread lowered the 'next' semaphore
# to raise the 'main' semaphore, indicating we can continue.
while ($line = <>) {
chomp $line;
thr_print "Main thread got '$line'
";
# notify service threads that a new line is ready
$next->up;
thr_print "Main thread set new line semaphore, waiting to proceed
";
# do not proceed until value has been retrieved by responding thread
$main->down;
thr_print "Main thread received instruction to proceed
";
}
thr_print "All lines processed, sending end signal
";
# set the line to special value 'undef' to indicate end of input
$line = undef;
# to terminate all threads, raise 'new line' semaphore to >= number of
# service threads: all service threads will decrement it and read the
# 'undef'
$next->up($threads);
thr_print "Main thread ended
";
exit 0;
# the thread subroutine--block on lock variable until work arrives
sub process_thing {
my $self = threads->self;
my $thread_line;
thr_print "Thread ", $self->tid, " started
";
while (1) {
# try to decrement 'next' semaphore--winning thread gets line
thr_print "Thread ", $self->tid, " waiting
";
$next->down;
# retrieve value to process
thr_print "Thread ", $self->tid, " signalled
";
$thread_line = $line;
# was this the 'quit' signal? Check the value sent
last unless (defined $thread_line);
# let main thread know we have got the value
thr_print "Thread ", $self->tid, " retrieved data, signaling main
";
$main->up;
# do private spurious things to it
chomp ($thread_line=uc($thread_line));
thr_print "Thread ", $self->tid, " got '$thread_line'
";
}
thr_print "Thread ", $self->tid, " ended
";
}
The semaphore version of the application is simpler than the condition variable implementation, if only because we have hidden the details of all the cond_wait
and cond_signal
functions inside calls to up
and down
. Instead of signaling the pool of service threads via a condition variable, the main thread simply raises the next semaphore by one, giving it the value 1
. Meanwhile, all the service threads are attempting to decrement this semaphore. One will succeed and receive the new line of input, and the others will fail, continuing to block until the semaphore is raised again. When it has copied the line to its own local variable, the thread raises the main semaphore to tell the main thread that it can proceed to read another line. The concept is recognizably the same as the previous example but is easier to follow.
We have also taken advantage of the fact that semaphores can hold any positive value to terminate the application. When the main thread runs out of input, it simply raises the "next" semaphore to be equal to the number of service threads. At this point, all the threads can decrement the semaphore, read the value of $line
that we again set to undef
, and quit. If a thread is still busy, the semaphore will remain positive until it finishes and comes back to decrement it—we have no need to put in an extra check in case we missed a signal.
Many threaded applications, our example a case in point, involve the transport of data between several different threads. In a complex application, incoming data might travel through multiple threads, passed from one to the next before being passed out again: a bucket-chain model. We can create pools of threads at each stage along the chain in a similar way to the preceding example application, but this does not improve upon the mechanism that allows each thread to pass data to the next in line.
The two versions of the application that we have produced so far are limited by the fact that they only handle a single value at a time. Before the main thread can read another line, it has to dispose of the previous one. Even though we can process multiple lines with multiple service threads, the communication between the main thread and the service threads is not very efficient. If we were communicating between different processes, we might use a pipe, which buffers output from one process until the other can read it; the same idea works for threads, too, and takes the form of a queue.
Perl provides support for queues through the Thread::Queue
module, which implements simple thread queues in a similar way to the semaphores created by Thread::Semaphore
. Rather than a single numeric flag, however, the queue consists of a list to which values may be added at one and removed from the other. At heart this is essentially no more than a shift
and pop
operation. Using conditional variables and locking the module, however, creates a queue that values may be added to and removed from safely in a threaded environment, following rules similar to those for semaphores:
The Thread::Queue
module provides a constructor and four object methods to create and manage queues. The new
constructor creates a new queue:
$queue = new Thread::Queue;
Values can be added to the queue, singly or in bulk, with the enqueue
method:
$queue->enqueue($value); # add a single value
$queue->enqueue(@values); # add several values
A single value can be removed with dequeue
. If no value is available, the method will block until one is available:
$value = $queue->dequeue; # remove a single value, block
If we don't want to risk getting blocked, dequeue_nb
removes a single value from a queue, if available, but returns undef
immediately, without blocking, if nothing is available:
$value = $queue->dequeue_nb; # remove a single value, don't block
if (defined $value) {
...
}
Finally, to check the number of values in the queue without actually removing one, we have the following pending:
print "There are ",$queue->pending," items in the queue
";
Using a queue, we can rewrite our threaded application again to separate the main thread from the pool of service threads. Since the queue can take multiple values, the main thread no longer has to wait for each value it passes on to be picked up before it can continue. This simplifies both the code and the execution of the program. The queue has no limit, however, so we make sure not to read too much by checking the size of the queue and yielding if it reaches a limit we choose. Here is a revised version of the same application using a queue:
#!/usr/bin/perl
# queue.pl
use warnings;
use strict;
use threads;
use Thread::Queue;
use Thread::Semaphore;
my $threads = 3; # number of service threads to create
my $maxqueuesize = 5; # maximum size of queue allowed
my $queue = new Thread::Queue; # the queue
my $ready = new Thread::Semaphore(0); # a 'start-gun' semaphore
# initialized to 0 each service
# thread raises it by 1
# a locked print subroutine - stops thread output mingling
sub thr_print : locked {
print @_;
}
# create a pool of service threads
foreach (1..$threads) {
threads->create(&process_thing, $ready, $queue);
}
# wait for all service threads to increment semaphore
$ready->down($threads);
# main loop: Read a line, queue it, read another, repeat until done
# yield and wait if the queue gets too large.
while (<>) {
chomp;
thr_print "Main thread got '$_'
";
# stall if we're getting too far ahead of the service threads
threads->yield while $queue->pending >= $maxqueuesize;
# queue the new line
$queue->enqueue($_);
}
thr_print "All lines processed, queuing end signals
";
# to terminate all threads, send as many 'undef's as there are service
# threads
$queue->enqueue( (undef)x$threads );
thr_print "Main thread ended
";
exit 0;
# the thread subroutine--block on lock variable until work arrives
sub process_thing {
my ($ready,$queue)=@_;
my $self=threads->self;
my $thread_line;
thr_print "Thread ",$self->tid," started
";
$ready->up; #indicate that we're ready to go
while (1) {
# wait for queue to deliver an item
thr_print "Thread ",$self->tid," waiting
";
my $thread_line=$queue->dequeue();
# was this the 'quit' signal? Check the value sent
last unless (defined $thread_line);
# do private spurious things to it
chomp ($thread_line=uc($thread_line));
thr_print "Thread ",$self->tid," got '$thread_line'
";
}
thr_print "Thread ", $self->tid, " ended
";
}
Since the service threads block if no values are waiting in the queue, the problem of having service threads wait is solved for us—we previously dealt with this using condition variables and semaphores. However, we don't need a return semaphore anymore because there is no longer any need for a service thread to signal the main thread that it can continue; the main thread is free to continue as soon as it has copied the new line into the queue.
The means by which we terminate the program has also changed. Originally, we set the line variable to undef
and broadcast to all the waiting threads. We replaced that with a semaphore, which we raised high enough so that all service threads could decrement it. With a queue, we use a variation on the semaphore approach, adding sufficient undef
values to the queue so that all service threads can remove one and exit.
We have added one further refinement to this version of the application—a "start-gun" semaphore. Simply put, this is a special semaphore that is created with a value of zero and is incremented by one by each service thread as it starts. The main thread attempts to decrement the semaphore by a number equal to the number of service threads, so it will only start to read lines once all service threads are running. Why is this useful? Because threads have no priority of execution. In the previous examples, the first service threads will start receiving and processing lines before later threads have even initialized. In a busy threaded application, the activity of these threads may mean that the service threads may never get the time to initialize themselves properly. In order to make sure we have a full pool of threads at our disposal, we use this semaphore to hold the main thread back until the entire pool is assembled.
The Thread::Status
module is a handy way to get debugging information from a threaded application. While it can be loaded directly into an application, it is more usual to load it from the command line:
> perl -MThread::Status mythrapp.pl
This will print to standard error, every five seconds, a report of all running threads. We can also control the output destination, output format, and number of stack frames (callers):
> perl -Mthread::Status=output,status.log,format=xml,callers=3 mythrapp.pl
Thread::Status
does have one drawback, however: it currently requires Thread::Signal
. This was a standard module prior to Perl 5.8 that is now mostly deprecated as a result of the introduction of "safe" signals.
In the older implementation of threads, applications that needed to handle process signals need to use the Thread::Signal
module in order to have signals delivered to threads reliably. The newer implementation does not quite replace it, however, so the older version is available from CPAN if needed (for example, for Thread::Status
).
In this chapter, we first looked at sending and receiving signals from Perl processes and writing signal handlers to deal with signals intelligently. We saw how the die
and warn
functions can be trapped with pseudo-signal handlers and investigated strategies and caveats in the implementation of signal-handling subroutines. We also examined the alarm signal and used it to trigger timed events to abort hung processes.
We went on to example multiprocessing applications and the use of fork
, both explicitly and implicitly via open
, to start up child processes. When creating child processes, it is very important to manage them properly and in particular collect or reap their exit status when they terminate. Alternatively, a child process can be made independent of its parent by changing its process group, also called daemonizing it. We also looked at communicating between processes using pipes, paired sockets, and Unix System V IPC: message queues, semaphores, and shared memory segments.
While fork
is a standard Unix system call, Windows has no equivalent concept, and so Perl instead emulates fork
using interpreter threads. This turns out to be a fairly impressive emulation that allows many multiprocessing Perl applications to run on Windows and Unix almost identically.
Finally, we looked at Perl's implementation of threads, newly overhauled in Perl 5.8. The new implementation of threads is called interpreter threads, and it differs from the older version in Perl 5.6 and earlier, in that data is not automatically shared between threads unless and until we ask for it. This is very different to most languages, notably C and C++, and means that the majority of Perl code will run in a threaded environment unaltered without needing to be aware of threads. Windows Perl is automatically threaded because it needs threads to emulate the fork system call. For Unix, we may need to rebuild Perl with thread support enabled in order to use it, as we covered back in Chapter 1.