我的主要过程产生了一个子进程.如果主要进程被杀死,则子进程将被赋予ppid 1.当子进入时,它将变为僵尸,因为init没有对此子进行wait()调用.有没有办法避免这种情况?
init 将调用wait()它继承的进程.僵尸应该只存在于孩子已经离开的地方但是父母还在,但还没有获得退出代码.从init联机帮助页:
init是系统上所有进程的父进程,它由内核执行,负责启动所有其他进程; 它是所有过程的父母,其天然父母已经死亡,并且有责任在他们死亡时收获这些过程.
你应该区分孤儿(他们还活着,他们的父母已经死了,因此他们已被收养init)和僵尸(他们死了,但他们的父母还活着,还没有收获).
孤儿在退出后会在很短的时间内成为僵尸,但在init收获之前,这个时期应该足够小,没有人注意到.事实上,所有现有的进程(除了可能init本身)都经历了这个短暂的僵尸阶段,只有那些父母没有足够快收获你注意到的情况.
initchild death(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;
}
Run Code Online (Sandbox Code Playgroud)
然后,稍后在主循环(不是信号处理程序)中,标记为进程表的任何进程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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2556 次 |
| 最近记录: |