Are Child Processes Created with Fork() Automatically Killed When the Parent Is Killed

Are child processes created with fork() automatically killed when the parent is killed?

No. If the parent is killed, children become children of the init process (that has the process id 1 and is launched as the first user process by the kernel).

The init process checks periodically for new children, and waits for them (thus freeing resources that are allocated by their return value).

The question was already discussed with quality answers here:
How to make child process die after parent exits?

How to make child process die after parent exits?

Child can ask kernel to deliver SIGHUP (or other signal) when parent dies by specifying option PR_SET_PDEATHSIG in prctl() syscall like this:

prctl(PR_SET_PDEATHSIG, SIGHUP);

See man 2 prctl for details.

Edit: This is Linux-only

Kill child process created with fork

When you fork a child, and then fail to wait() on it, it will become a defunct process (a zombie in Unix parlance) when it exits. You'll notice that its parent process ID becomes 1, and it will not go away until the OS rebooted.

So the traditional pseudocode for forking looks something like this:

if ($pid = fork()) {
# pid is non-zero, this is the parent
waitpid($pid) # tell OS that we care about the child

do other parental stuff
}
else {
# pid is 0 so this is the child process
do_childish_things()
}

Your code doesn't do that, so you're probably getting zombies, and then getting frustrated that you can't get rid of them.

How to keep child process active when parent is killed/finished (in windows)

  1. In Windows, when you kill the parent process, its children are also killed. (Not like Linux, where after the parent is killed, children get their new parent -INIT with PID 1).
  2. In windows, the parent will also not exit automatically (parent PID will be present) if the child is still running. (For your question).

So, the solution would be that you add a step where before ending of the main script, child PID is killed; and so as when child will be killed, the parent would also be able to exit successfully.

So, now if your main script finishes before the threshold time, it means no action is required by the child (And also, child will be killed before the main script completes). And if the main script crosses the threshold, the child will send a mail. And when the main script will be about to end, child will be killed first, and the main script can get exited successfully.

Killing child process one by one

I Think you can use an array with global scope to safe children's pid and then use it into the function kill_child calling: int kill(pid_t pid, int sig).
Inside kill_child, I think you can send SIGKILL to children or redefine behavior with signal function if you want to send SIGTERM.
This can be a solution.
Aniway, I noticed something that can be improved (in my humble opinion) in your code:

  1. I'm not sure that your program will print "Hi, i am a parent\n" because you can't be sure that at least one child has pid = 1(unless you are sure of it for other reasons)
  2. The while loop create a lot of overhead because every second you reactivate a process and this process sooner or later take the CPU only for call sleep to wait one second

I hope I have helped you!

Kill children when the parent is killed

Note   The second example, using END block, is more complete.

Note   Discussion of how to use the process group for this is at the end.


Most of the time chances are that you are dealing with SIGTERM signal. For this you can arrange to clean up child processes, via a handler. There are signals that cannot be trapped, notably SIGKILL and SIGSTOP. For those you'd have to go to the OS, per answer by Kaz. Here is a sketch for others. Also see other code below it, comments below that, and process group use at the end.

use warnings;
use strict;
use feature qw(say);
say "Parent pid: $$";

$SIG{TERM} = \&handle_signal; # Same for others that can (and should) be handled

END { say "In END block ..." }

my @kids;
for (1..4) {
push @kids, fork;
if ($kids[-1] == 0) { exec 'sleep 20' }
}
say "Started processes: @kids";
sleep 30;

sub handle_signal {
my $signame = shift;
say "Got $signame. Clean up child processes.";
clean_up_kids(@kids);
die "Die-ing for $signame signal";
};

sub clean_up_kids {
say "\tSending TERM to processes @_";
my $cnt = kill 'TERM', @_;
say "\tNumber of processes signaled: $cnt";
waitpid $_, 0 for @_; # blocking
}

When I run this as signals.pl & and then kill it, it prints


[13] 4974
Parent pid: 4974
Started processes: 4978 4979 4980 4982
prompt> kill 4974
Got TERM. Clean up child processes.
Sending TERM to processes 4978 4979 4980 4982
Number of processes signaled: 4
Die-ing for TERM signal at signals.pl line 25.
In END block ...

[13] Exit 4 signals.pl

The processes do get killed, checked by ps aux | egrep '[s]leep' before and after kill.

By courtesy of die the END block gets executed orderly so you can clean up child processes there. That way you are also protected against uncaught die. So you'd use the handler merely to ensure that the END block cleanup happens.

use POSIX "sys_wait_h";
$SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) { } }; # non-blocking
$SIG{TERM} = \&handle_signal;

END {
clean_up_kids(@kids);
my @live = grep { kill 0, $_ } @kids;
warn "Processes @live still running" if @live;
}

sub clean_up_kids {
my $cnt = kill 'TERM', @_;
say "Signaled $cnt processes.";
}
sub handle_signal { die "Die-ing for " . shift }

Here we reap (all) terminated child processes in a SIGCHLD handler, see Signals in perlipc and waitpid. We also check in the end whether they are all gone (and reaped).

The kill 0, $pid returns true even if the child is a zombie (exited but not reaped), and this may happen in tests as the parent checks right after. Add sleep 1 after clean_up_kids() if needed.

Some notes. This is nowhere near to a full list of things to consider. Along with mentioned (and other) Perl docs also see UNIX and C documentation as Perl's ipc is built directly over UNIX system tools.

  • Practically all error checking is omitted here. Please add

  • Waiting for particular processes is blocking so if some weren't terminated the program will hang. The non-blocking waitpid has another caveat, see linked perlipc docs

  • Child processes may have exited before the parent was killed. The kill 'TERM' sends SIGTERM but this doesn't ensure that the child terminates. Processes may or may not be there

  • Signal handlers may get invalidated in the END phase, see this post. In my tests the CHLD is still handled here but if this is a problem re-install the handler, as in the linked answer

  • There are modules for various aspects of this. See sigtrap pragma for example

  • One is well advised to not do much in signal handlers

  • There is a lot going on and errors can have unexpected and far ranging consequences


If you kill the process group you won't have any of these issues, since all children are then terminated as well. On my system this can be done at the terminal by


prompt> kill -s TERM -pid

You may have to use a numeric signal, generally 15 for TERM, see man kill on your system. The -pid stands for the process group, signified by the minus sign. The number is the same as the process ID, but add say getpgrp; to the code to see. If this process has not been simply launched by the shell, but say from another script, it will belong to its parent's process group, and so will its children. Then you need to set its own process group first, which its children will inherit, and then you can kill that process group. See setpgrp and getpgrp.



Related Topics



Leave a reply



Submit