belg4mit has asked for the wisdom of the Perl Monks concerning the following question:

Okay so the following code is supposed to:

loop infinitely
 have a nested loop that iterates n times (in this case 10) 
  within the nested loop there is a conditional fork (fork on 6th loop)
  sleep after completing the nested loop

Instead it proceeds as expected initially but after a few (2) iterations there are mutliple children which execute simultaneously... The problem goes away if I remove the CHLD handler, but then I have zombie children... If I set CHLD to IGNORE the problem goes away (though I always have *one* zombie)

It seems to be related to the fact that it is somehow running through the nested loop multiple times?

Looping 6 (28680) ...
I am child 28682 [0]
Looping 6 (28680) ...

Any ideas?

sub REAPER { $waitedpid = wait; print "GOT PID: $waitedpid\n"; $SIG{CHLD} = \&REAPER; } $SIG{CHLD} = \&REAPER; while(1){ my $i=0; print scalar localtime(time()), "\n"; for(;$i<10;$i++){ print "Looping $i ($$) ...\n"; if( $i == 5 ){ if( ! defined($pid = fork) ){ print "Danger danger Will Robinson!\n"; } unless( $pid ){ print "I am child $$ [$pid]\n"; exit 0; } } } sleep 5; }

Replies are listed 'Best First'.
Re: Problem with children (out of conrol forking vs. zombies)
by merlyn (Sage) on Oct 12, 2001 at 01:53 UTC
    You will get one SIGCHLD for any appearance of one or more kids. You have to reap kids until there are no kids to reap. Something like this:
    use POSIX qw(WNOHANG); while ((my $kid = waitpid(-1, WNOHANG)) > 0) { warn "$kid reaped\n" if $trace; delete $kids{$kid}; }
    Ripped off from my column about stuff like that.

    The best way is to simply do this polling at some opportune time in your main loop, since having it in a signal handler will break eventually.

    -- Randal L. Schwartz, Perl hacker