Wait for children to complete if parent intercepts

2019-09-12 02:29发布

问题:

I have a perl script with multiple child processes (created using fork()). Each child sleeps then does some processing (several system() calls). Under windows when I hit Ctrl+C I see that the signal was caught , then the script waits for the children to complete and after this exits. I want to replicate this behaviour in linux (catch sigint , let the children complete and exit the main script/process ).

How do I wait for all children to complete before killing the parent ? Is it possible to exit the main script / kill the parent , but let the children complete in the background ?

I found Child process receives parent's SIGINT , and it seems SIGINT is propagated to the children (the process group) , so to avoid this I'd have to set the child in a different process group.

$SIG{'INT'} = sub {
    print "Caught Ctrl+C\n";
    die "Stopping...";
};

++$|;

print "Start\n";
for($i=0; $i < 500; $i++) {
    sleep 3;
    $childPid = fork(); #fork a process
    if($childPid == 0){
        print "Child $i...\n";
        sleep 10;
        system("echo finishing");
        print "Exit child $i\n";
        exit;
    }
}

I also tried to include this in the SIGINT processing block , but the for loop isn't paused , so new child processes are created and parent doesn't die.

# I used my $parentPid = $$; (before  the for loop) to get the parent pid.

if ($$ = $parentPid){
    foreach $var (@pids) {
        $pid = waitpid($var ,0);
    }  

EDIT:

Tried setting the child SIGINT handler to IGNORE and it works as expected. In the parent handler I do :

$SIG{'INT'} = sub {
  print "Caught Ctrl+C by $$\n";
  # while($result != -1){
      # $result = wait();
  #}
    die "Stopping...";
}; 

a) If include the commented lines the script waits for the children to complete and then exits.

b) But if I comment the "wait" lines I assume it works like this

  1. the script exits and the parent process is terminated
  2. the children continue running in the background and display "Exit child" message as expected before exiting.

I understand the a) case but how does the b) case work, please explain why doesn't this generate zombie processes ?

回答1:

Under windows when I hit Ctrl+C I see that the signal was caught , then the script waits for the children to complete and after this exits.

I think this is a side-effect of the psuedo-fork implementation.

How do I wait for all children to complete before killing the parent ?

The easiest way is to ignore the SIGINT In the children, and wait/waitpid in the parents SIGINT handler.

I also tried to include this in the SIGINT processing block , but the for loop isn't paused , so new child processes are created and parent doesn't die.

I think you meant $$ == $parentPid (comparison instead of assignment). Also, it's not really useful to specify which child you're waiting for if you're waiting for all of them anyway.



标签: perl fork