use strict; use warnings; require POSIX; # provides WNOHANG # Set up a signal handler. # This prevents child processes from becoming zombies. # The subroutine is defined further below. $SIG{CHLD} = \&reap_kids; # Track spawned child processes. # This is a hash, keyed by the PID. # We'll use this later to mark them as finished. my %kids; for my $child_id (1..3) { my $pid = fork(); # PARENT: track kid if ($pid) { $kids{$pid} = 1; } # CHILD: dispatch to child-routine below. # Explicitly exit, in case the child code neglects. else { dispatch_child( $child_id ); exit(0); } } print "Main code now waiting for all children.\n"; # Wait for all children to finish. # The signal handler, reap_kids(), catches finished children. # Just continue to sleep if there are pending processes. while( scalar(keys %kids) > 0 ) { sleep 1; } # That's all the main code does. print "All done with main code.\n"; exit(0); # --- # Suborutines # --- # Child reaper. # This will be called when the kernel tells us a process has # finished running. It's possible more than 1 has done so. # We run this in a loop to reap all children. sub reap_kids { local $!; # good practice. avoids changing errno. while (1) { my $kid = waitpid( -1, POSIX->WNOHANG ); last unless ($kid > 0); # No more to reap. delete $kids{$kid}; # untrack kid. } } # Child dispatch code. # Here is where you write what your child does. # Ideally it should exit, but we enforce this above anyway. sub dispatch_child { my $id = shift; # passed from caller. print "Hello from child number $id\n"; # Sleep for a random number of seconds. # Between 5 and 10. my $seconds = 5 + int(rand(6)); sleep $seconds; print "Goodbye from child number $id\n"; # Be nice and explicitly exit: exit(0); }