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
- the script exits and the parent process is terminated
- 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 ?
I think this is a side-effect of the psuedo-fork implementation.
The easiest way is to ignore the
SIGINT
In the children, andwait
/waitpid
in the parentsSIGINT
handler.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.