Still another way of creating an additional process is to clone the current Perl process using a UNIX primitive called
fork
. The
fork
function simply does what the
fork
(2) system call does: it creates a clone of the current process. This clone (called the
child, with the original called the
parent) shares the same executable code, variables, and even open files. To distinguish the two processes, the
return value from
fork
is zero for the child, and nonzero for the parent (or
undef
if the system call fails). The nonzero value received by the parent happens to be the child's process ID. You can check for the return value and act accordingly:
if (!defined($child_pid = fork())) {
die "cannot fork: $!";
} elsif ($child_pid) {
# I'm the parent
} else {
# I'm the child
}
To best use this clone, we need to learn about a few more things that parallel their UNIX namesakes closely: the
wait
,
exit
, and
exec
functions.
The simplest of these is the
exec
function. It's just like the
system
function, except that instead of firing off a new process to execute the shell command, Perl replaces the current process with the shell. (In UNIX parlance, Perl
exec
's the shell.) After a successful
exec
, the Perl program is gone, having been replaced by the requested program. For example,
exec "date";
replaces the current Perl program with the
date
command, causing the output of the
date
to go to the standard output of the Perl program. When the
date
command finishes, there's nothing more to do because the Perl program is long gone.
Another way of looking at this is that the
system
function is like a
fork
followed by an
exec
, as follows:
# METHOD 1... using system:
system("date");
# METHOD 2... using fork/exec:
unless (fork) {
# fork returned zero, so I'm the child, and I exec:
exec("date"); # child process becomes the date command
}
Using
fork
and
exec
this way isn't quite right though, because the
date
command and the parent process are both chugging along at the same time, possibly intermingling their output and generally mucking things up. What we need is a way to tell the parent to wait until the child process completes. That's exactly what the
wait
function does; it waits until the
child (any child, to be precise) has completed. The
waitpid
function is more discriminating: it waits for a specific child process to complete rather just any kid:
if (!defined($kidpid = fork())) {
# fork returned undef, so failed
die "cannot fork: $!";
} elsif ($kidpid == 0) {
# fork returned 0, so this branch is the child
exec("date");
# if the exec fails, fall through to the next statement
die "can't exec date: $!";
} else {
# fork returned neither 0 nor undef,
# so this branch is the parent
waitpid($kidpid, 0);
}
If this all seems rather fuzzy to you, you should probably study up on the
fork
(2) and
exec
(2) system calls in a traditional UNIX text, because Perl is pretty much just passing the function calls right down to the UNIX system calls.
The
exit
function causes an immediate exit from the current Perl process. You'd use this to abort a Perl program from somewhere in the middle, or with
fork
to execute some Perl code in a process and then quit. Here's a case of removing some files in
/tmp
in the background using a forked Perl process:
unless (defined ($pid = fork)) {
die "cannot fork: $!";
}
unless ($pid) {
unlink </tmp/badrock.*>; # blast those files
exit; # the child stops here
}
# Parent continues here
waitpid($pid, 0); # must clean up after dead kid
Without the
exit
, the child process would continue executing Perl code (at the line marked
Parent
continues
here
), and that's definitely not what we want.
The
exit
function takes an optional parameter, which serves as the numeric
exit value that can be noticed by the parent process. The default is to exit with a zero value, indicating that everything went OK.