http://www.perlmonks.org?node_id=932538


in reply to Re^4: Monitoring Child Process
in thread Monitoring Child Process

Ok, I'm back from my meeting and wrote some more code for you.

Some changes:
- while ( sleep(1), @dead_kids < @all_kids) {} will wait until the number of dead_kids is the same as all_kids. note: scalar in front of @all_kids is redundant. I've used both of these arrays in a scalar context. The sleep() is so that we don't burn CPU while looping. Handling SIGCHLD seems to prematurely end the sleep, but this code restarts the sleep if we aren't done. In Perl I think sleep() is implemented in terms of alarm() and I will admit something a bit weird is going on here that I don't fully understand although my workaround appears to be fine.

- the $SIG{INT} = 'IGNORE'; in the child code is important. If you leave it in there, then hitting CTL-C will print the the currently running kids and then resume normal operation. If you comment that line out, then normal CTL-C handling is in effect for the children and they will exit. The CTL-C handler is only installed for the parent. The child either ignores CTL-C or has normal handling for it. On my Linux test machine, when this code is running in the foreground, everybody (all kids and the parent) get CTL-C if I hit that.

Interesting problem. Have fun with this code. I didn't worry about efficiency in sub ctlc - I think the main point here is how to handle the signals and what to do when.

#!/usr/bin/perl -w use strict; use POSIX qw(:sys_wait_h); $SIG{CHLD} = \&REAPER; $|=1; #turn off STDOUT buffering my (@all_kids, @dead_kids); my @array = qw(a b c d e f g h); for (1 .. 10) { die "Bad Fork! $!\n" if ( !defined(my $pid = fork()) ); if ($pid ==0) #I'm child { $SIG{INT} = 'IGNORE'; #### comment out to exit on CTL-C my $t = int(rand(5))+1; print "@array sleeping $t secs\n"; sleep ($t); exit (0); } push (@all_kids, $pid); #I'm parent print "Started another child process - $pid.\n"; } print "All child processes have started...\n"; print "kids are: @all_kids\n"; $SIG{INT} = \&ctlc; #CTL-C handler in parent only while ( sleep(1), @dead_kids < @all_kids) {} #wait for kids to finish print "dead kids: @dead_kids\n"; print "All child processes are finished\n"; sub REAPER { my $pid; while ( ($pid = waitpid(-1, WNOHANG)) > 0) { print "Process $pid exited.\n"; push @dead_kids, $pid; } } sub ctlc { print "***** Ctrl-C Trap\n"; my %dead = map{$_ => 1}@dead_kids; print "still alive: "; foreach my $kid (@all_kids) { print "$kid " if !$dead{$kid}; } print "\n"; print "***** Ctrl-C Trap end\n"; }

Replies are listed 'Best First'.
Re^6: Monitoring Child Process
by Anonymous Monk on Oct 20, 2011 at 04:00 UTC
    Thank you very much. I didn't notice your reply as I was trying and playing with your code. I will test this tomorrow and will let you know.
      I did test my most recent code on a 64 bit, 4 core Linux machine running Active State 5.12. I claim that it "works as advertised" on my test machine.

      Run the code and see what happens...

        Thank you. This works really great!