我的主要过程产生了一个subprocess。 如果主进程被杀死,那么这个孩子将被指派为1。当这个孩子退出时,它将成为一个僵尸,因为init没有在这个孩子上调用wait()。 有没有办法避免这种情况?
init
会在它继承的进程上调用wait()
。 僵尸应该只存在于孩子已经离开的地方,但父母仍然在附近,但还没有获得退出代码。 从init
页:
init
是系统上所有进程的父进程,由内核执行并负责启动所有其他进程; 它是自然父母死亡的所有过程的母体,死亡时负责收割。
你应该区分孤儿(他们还活着,他们的父母已经死了,因此他们已经通过init
),僵尸(他们已经死了,但他们的父母还活着,还没有收获)。
孤儿在离开之后,在init
收获之前,会在很短的时间内成为僵尸,但这个时期应该足够小,以至于没有人注意到。 实际上, 所有正在进行的进程(除了可能的init
本身)都会经历这个短暂的僵尸阶段,只有那些父母没有及时收获的情况下,你才会注意到。
init
child child( SIGCHLD
)处理程序中的实际代码如下所示(我的注释):
void chld_handler (int sig) { CHILD *ch; int pid, st; int saved_errno = errno; while ((pid = waitpid(-1, &st, WNOHANG)) != 0) { // << WAIT done here if (errno == ECHILD) break; for (ch = family; ch; ch = ch->next) { if (ch->pid == pid && (ch->flags & RUNNING)) { INITDBG (L_VB, child_handler: marked %d as zombie", ch->pid); ADDSET (got_signals, SIGCHLD); ch->exstat = st; ch->flags |= ZOMBIE; // Set to zombie here. if (ch->new) { ch->new->exstat = st; ch->new->flags |= ZOMBIE; } break; } } if (ch == NULL) { INITDBG (L_VB, "chld_handler: unknown child %d exited.", pid); } } errno = saved_errno; }
然后,在主循环(不是信号处理程序)的后面,清理标记为ZOMBIE
的进程表中的所有进程:
if (ISMEMBER (got_signals, SIGCHLD)) { INITDBG(L_VB, "got SIGCHLD"); /* First set flag to 0 */ DELSET(got_signals, SIGCHLD); /* See which child this was */ for (ch = family; ch; ch = ch->next) { if (ch->flags & ZOMBIE) { // ZOMBIE detected here INITDBG (L_VB, "Child died, PID= %d", ch->pid); ch->flags &= ~(RUNNING|ZOMBIE|WAITING); // And cleared here. if (ch->process[0] != '+') { write_utmp_wtmp ("", ch->id, ch->pid, DEAD_PROCESS, NULL); } } } }
在程序的最后放置一个等待(NULL)语句,以便父母和孩子正在彼此等待,直到他们都完成其执行,并且从任何人都不成为僵尸进程。