简体   繁体   中英

How can i prevent a child process to NOT become a zombie if parent exits

My main process spawns a child process. If the main process is killed, the child would be assigned ppid of 1. When the child exits, it would become a zombie as init has not called wait() on this child. Is there a way to avoid this situation?

init will call wait() on processes that it inherits. Zombies should only exist where the child has exited but the parent is still around, but is yet to reap the exit code. From the init manpage:

init is the parent of all processes on the system, it is executed by the kernel and is responsible for starting all other processes; it is the parent of all processes whose natural parents have died and it is responsible for reaping those when they die.

You should make a distinction between orphans (they're still alive, their parent is dead and hence they've been adopted by init ), and zombies (they're dead but their parent is alive and has not yet reaped them).

Orphans will become zombies for a very short period of time after they exit but before init reaps them but this period should be small enough that no-one notices. In fact, all exiting processes (except possibly init itself) go through this short zombie phase, it's only those cases where the parent doesn't reap quickly enough that you notice.


The actual code in the init child death ( SIGCHLD ) handler goes something like this (my comments):

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;
}

And then, later on in the main loop (not signal handler), any processes in the process table marked as ZOMBIE are cleaned up:

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)语句,以便父和子等待彼此,直到它们都完成执行并且从任何人都不成为僵尸进程。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM