When a child process forked from a parent dies, it still exists to some extent and is left in a zombie state, until it is reaped from a wait() call.
Is is possible to detach this parent-child relationship and have the children be automatically reaped? Maybe orphan off the child to init, or something?
Possible use case: Creating a lot of fire-and-forget processes in a long-lived program, without "holding" on to an increasing list of zombie PIDs that cannot be recycled by the OS.
Per the POSIX _exit() documentation:
If the parent process of the calling process has set its
SA_NOCLDWAIT
flag or has set the action for the SIGCHLD
signal to
SIG_IGN
:
The process' status information (see Status Information), if any, shall be discarded.
The lifetime of the calling process shall end immediately. If SA_NOCLDWAIT
is set, it is implementation-defined whether a SIGCHLD
signal is sent to the parent process.
If a thread in the parent process of the calling process is blocked in wait()
, waitpid()
, or waitid()
, and the parent process has
no remaining child processes in the set of waited-for children, the
wait()
, waitid()
, or waitpid()
function shall fail and set errno
to [ECHILD
].
Otherwise:
Status information (see Status Information) shall be generated.
The calling process shall be transformed into a zombie process. Its status information shall be made available to the parent process
until the process' lifetime ends.
...
In short, to prevent child processes from becoming zombie processes, the simplest way is to call sigignore( SIGCHLD );
UPDATE
That does impact the ability to wait for any child process, which may not be desired. The setsid()
library function allows a process to disassociate itself from its parent:
pid_t child = fork();
if ( ( pid_t ) 0 == child )
{
int rc = setsid();
rc = execv(...);
}
else ...
The disassociated child process doesn't create a zombie nor send SIGCHLD
to the parent process on my installed instance of Solaris 11.2.
This is an abbreviated daemonization of a "fire-and-forget" child process, only doing what is necessary to prevent creating a zombie or sending SIGCHLD
to the parent process. For a much fuller daemonization procedure, see Linux daemonize
As of Python 3.2, you can use subprocess.Popen() and pass start_new_session=True to accomplish this.
The docs state:
If start_new_session is true the setsid() system call will be made in the child process prior to the execution of the subprocess. (POSIX only)
https://docs.python.org/3/library/subprocess.html#subprocess.Popen
Note that this does not allow one "to do this from the parent at an arbitrary stage in the child's lifetime" as mentioned in a follow-up comment.