【发布时间】:2018-03-19 04:31:09
【问题描述】:
当从父进程派生的子进程死亡时,它在一定程度上仍然存在并处于僵尸状态,直到从 wait() 调用中恢复。
是否可以分离这种父子关系并让孩子自动收割?可能是孤儿了,还是什么的?
可能的用例:在一个长期存在的程序中创建大量即发即弃的进程,而不是“持有”越来越多的无法被操作系统回收的僵尸 PID。
【问题讨论】:
标签: unix posix child-process
当从父进程派生的子进程死亡时,它在一定程度上仍然存在并处于僵尸状态,直到从 wait() 调用中恢复。
是否可以分离这种父子关系并让孩子自动收割?可能是孤儿了,还是什么的?
可能的用例:在一个长期存在的程序中创建大量即发即弃的进程,而不是“持有”越来越多的无法被操作系统回收的僵尸 PID。
【问题讨论】:
标签: unix posix child-process
每the POSIX _exit() documentation:
如果调用进程的父进程已经设置了它的
SA_NOCLDWAIT标志或已将SIGCHLD信号的操作设置为SIG_IGN:
进程的状态信息(见状态信息),如果有的话,应该被丢弃。
调用进程的生命周期应立即结束。如果设置了
SA_NOCLDWAIT,则由实现定义是否SIGCHLD信号被发送到父进程。如果调用进程的父进程中的某个线程在
wait()、waitpid()或waitid()中被阻塞,并且父进程有 在等待的子集中没有剩余子进程,wait()、waitid()或waitpid()函数将失败并设置errno到 [ECHILD]。否则:
应生成状态信息(参见状态信息)。
调用进程应转化为僵尸进程。其状态信息应提供给父进程 直到进程的生命周期结束。
...
总之,为了防止子进程变成僵尸进程,最简单的方法就是调用sigignore( SIGCHLD );
更新
这确实会影响等待任何子进程的能力,这可能是不希望的。 setsid() library function 允许进程将自己与其父进程解除关联:
pid_t child = fork();
if ( ( pid_t ) 0 == child )
{
int rc = setsid();
rc = execv(...);
}
else ...
在我安装的 Solaris 11.2 实例上,解除关联的子进程不会创建僵尸进程,也不会向父进程发送 SIGCHLD。
这是“即发即弃”子进程的缩写守护进程,仅执行必要的操作以防止创建僵尸或将SIGCHLD 发送到父进程。有关更完整的守护程序,请参阅Linux daemonize
【讨论】:
fork() 之后和execv*() 之前使用setsid() 以允许子进程对父进程“隐藏”,而不是创建僵尸或在终止时发送SIGCHLD。
setsid() 是异步信号安全的,因此您可以简单地在子进程代码中创建一个信号处理函数,在您选择的信号上调用 setsid(),例如 SIGUSR1 ,或实时信号之一SIGRTMIN + n。然后,当您想阻止子进程发送父进程SIGCHLD 时,只需调用kill( pid, SIGUSR1 ); 让子进程调用其信号处理程序。
setsid 不会阻止孩子被收割/变成僵尸。它只会在默认设置中阻止ps 显示这样一个僵尸孩子。但它仍然是一个僵尸(ps 仍然可以显示它,例如,如果你给 ps 孩子的确切 pid)。
从 Python 3.2 开始,您可以使用 subprocess.Popen() 并传递 start_new_session=True 来完成此操作。
文档状态:
如果 start_new_session 为真,setsid() 系统调用将在子进程执行之前在子进程中进行。 (仅限 POSIX)
https://docs.python.org/3/library/subprocess.html#subprocess.Popen
请注意,这不允许“在孩子一生中的任意阶段从父母那里做到这一点”,如后续评论中所述。
【讨论】:
忽略SIGCHLD 或为SIGCHLD 安装一个带有SA_NOCLDWAIT 标志的sighandler 可防止所有孩子成为僵尸(/成为wait-able)。
要为单个孩子执行此操作,您可以在启动孩子时使用不带 SIGCHLD 标志的 Linux 的 clone(),或者您可以加倍 fork(或 vfork,如果您知道如何安全地这样做) .然后孩子可以立即_exit(0) 并被其父母wait-ed,孙子可以继续做实际的工作(如你所说,重新成为init)。
(双叉的轻微扩展将是完全妖魔化,其中子或孙子也调用setsid来创建新会话、新进程组并与控制终端分离。setsid单独不会阻止孩子成为僵尸。它只会在默认设置中对ps 隐藏僵尸,而ps 仅显示当前终端控制会话中的进程。)
【讨论】: