On 4/6/06, Mr. Shawn H. Corey <[EMAIL PROTECTED]> wrote:
snip
> Zombies happen for two reasons. The first it that it is waiting for its
> parent to harvest its status code.
snip

Just to expand on this, there are several methods of harvesting the
status code of your children.  The first is simply wait for the child
to finish (this is sortof what system() does):

sub simple_system {
    my $pid = fork;
    die "could not fork" unless defined $pid;
    if ($pid) {
        wait();
        return $?;
    } else {
        exec "@_";
    }
}

Using wait() in that way is dangerous if you have more than one child
since wait returns as soon as any child exits.  A beter way is to wait
specifically for the pid you are looking for like this

sub still_simple_system {
    my $pid = fork;
    die "could not fork" unless defined $pid;
    if ($pid) {
        waitpid($pid);
        return $?;
    } else {
        exec "@_";
    }
}

Both of the examples above assumed you wanted to wait for child to
finish, but most of the time you have several children you want to
manage and you don't want to block the main loop until one dies.  In
that case you can call waitpid() with a WNOHANG option like this:

use POSIX ":sys_wait_h";
#fork a bunch of times
while ($continue) {
    my $pid = waitpid(-1, &WNOHANG);
    if ($pid > 0) {
        print "process $pid ended with $?\n";
    }
    #do other things
    sleep 5; #wait a bit before running the main loop again
}

Now, all of this has been assuming you care about your children, but I
hate the little buggers.  I don't care what they do in life; if they
have a problem, they should either handle it or die().  I just want
their statuses to be reaped automatically without my having to look at
them.  Luckily, Perl supports this by letting me put the following
line in my program

$SIG{CHLD} = 'IGNORE';

You can also use $SIG{CHLD} to install a handler if you are not as
heartless as I am.  This is similar to calling waitpid() in your main
loop, but has the benefit of handling all children as soon as
possible.  The only drawback is that make the code harder to read and
debug (since it is hard to predict exactly when the handler will run).

use POSIX ":sys_wait_h";

my $handler = sub {
    my $pid;
    while (($pid = waitpid(-1, &WNOHANG)) > 0) {
        # do something with $pid
    }
    $SIG{CHLD} = $handler #reinstall the handler
}
$SIG{CHLD} = $handler;

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to