Detach child process from parent

2020-03-02 06:32发布

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.

2条回答
够拽才男人
2楼-- · 2020-03-02 06:57

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

查看更多
淡お忘
3楼-- · 2020-03-02 07:01

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.

查看更多
登录 后发表回答