My version will spawn N number of children immediately and then
spawn one more every time an already existing child dies until
a job queue is exhausted. It will then wait for every existing
child to die. Oh, it also prints a message before spawning
a new child.
Notice I never install a SIGCHLD handler.
That is because the parent will process them itself. Also, the
waitpids are done non-blocking. The sleep makes sure we do
not loop too tightly.
As splinky said, if you call a subroutine, make sure it exits
or you call exit after it returns. The original code I took
this from actually exec'd and so I didn't worry about it.
$num_children is a command line arg, not shown here so you don't
have to see my lame mp3 ripping code. It, obviously, controls
how many child procs will be spawned.
# Interesting stuff has happened to load the job queue and par
# the command line, and whatever else you want to happen.
sub SPAWN {
$counter++;
if ( $cpid = fork ) {
$tracker{$cpid} = $ref->[1];
}
else {
# This can be a call like this, or
my_sub( @_ );
exit;
# You can exec some external proc like
# exec "/bin/ls -FC /var";
}
}
my $dpid = 0;
while( @job_q ) {
my $ref = shift @job_q;
#--
# Initial loop to spawn children
#--
if ( $counter < $num_children ) {
&SPAWN( $ref );
}
else {
do {
sleep 5;
$dpid = waitpid( -1, 1 );
} until $dpid;
last if ( $dpid == -1 ); # No children left
printf "%s has finished, spawning next child (%d left)\n", $tr
+acker{$dpi
d}, scalar @job_q;
&SPAWN( $ref );
}
}
do {
sleep 5;
$dpid = waitpid( -1, 1 );
printf("%s has finished\n", $tracker{$dpid}) if(defined( $tracker{
+$dpid} )
);
} until $dpid == -1;
I will warn you this isn't the most robust code. I haven't had
problems with it, but it is something only I use. It is a
slightly different solution to the problem though.
mikfire |