Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^3: Monitoring Child Process

by Marshall (Prior)
on Oct 19, 2011 at 20:08 UTC ( #932491=note: print w/ replies, xml ) Need Help??


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

Oh, I guess a mis-communication. I updated my post with a more detailed suggestion. This foreach(@all_kids) code is that part should be deleted!

The REAPER is part of the parent. So having waitpid() in only one place means having it only in REAPER().

Some replacement code to this foreach (@all_kids) loop:

while (@dead_kids <10) { sleep(1); } print "all kids dead .. @dead_kids\n";
You can also just sleep(20) and print @dead_kids. The focus right now should be on getting this to work without the CTL-C complication and then add that later.

Update: Oh, I would also add use warnings; either by that statement, or a -w in the hash bang line. This has nothing to do with your current woes, but there are run time checks with warnings enabled that are useful. I leave them on unless some rare, very rare performance or other reason indicates otherwise.

Another Update: Was able to test some code...for some reason, when SIGCHLD happens, this causes the sleep to end. I don't know why. So there is a loop to restart the sleep every 1 seconds. try this code...have to run to an appointment...oh, exit 1 was caused by missing parens in while statement in the reaper. The sleep issue is the real puzzle here.

update: added readmore tag - updated code in later post

#!/usr/bin/perl -w use strict; use POSIX qw(:signal_h :errno_h :sys_wait_h); $SIG{CHLD} = \&REAPER; 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 { my $t=int(rand(5))+1; print "@array sleeping $t secs\n"; sleep ($t); exit (0); } push (@all_kids, $pid); #I'm parent print "Starting another child process - $pid.\n"; } print "All child processes have started...\n"; print "kids: @all_kids\n"; my $count=0; while ($count <20) { sleep(1); $count++; } print "dead kids: @dead_kids\n"; print "All child processes are finished???\n"; sub REAPER { my $pid; while ( ($pid = waitpid(-1, WNOHANG)) > 0) #missed paren before { print "Process $pid exited.\n"; push @dead_kids, $pid; } return; }
<\readmore>


Comment on Re^3: Monitoring Child Process
Select or Download Code
Re^4: Monitoring Child Process
by Anonymous Monk on Oct 19, 2011 at 20:43 UTC
    Thank you very much. The normal condition works now where it is able to monitor the child process.

    But the ctrl-c condition where I press the ctrl-c does not seem to be working. Maybe my testing is just wrong, but when I press ctrl-c, I do not see any other running child process.
    while (@dead_kids < scalar @all_kids ) { print "dead kids: ", scalar @dead_kids, "\n";; sleep 1; # This is where I want to test the ctrl-c. sleep 5 if ( @dead_kids > 1 ); }
      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"; }
        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.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://932491]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2014-08-01 00:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (256 votes), past polls