Why zombie processes exist?
Asked Answered
B

1

12

Wikipedia says "A child process that terminates but is never waited on by its parent becomes a zombie process." I run this program:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t pid, ppid;
    printf("Hello World1\n");
    pid=fork();
    if(pid==0)
    {
        exit(0);    
    }
    else
    {
        while(1)
        {
        printf("I am the parent\n");
        printf("The PID of parent is %d\n",getpid());
        printf("The PID of parent of parent is %d\n",getppid());        
        sleep(2);
        }
    }
}

This creates a zombie process, but I can't understand why a zombie process is created here?

The output of the program is

Hello World1
I am the parent
The PID of parent is 3267
The PID of parent of parent is 2456
I am the parent
The PID of parent is 3267
The PID of parent of parent is 2456
I am the parent
....
.....

But why is it that the "child process terminates but is not waited on by its parent" in this case?

Boomerang answered 18/4, 2013 at 9:17 Comment(5)
Are you asking why the concept of a zombie process was introduced in Unix? As it stands, the only answer to your question that I see is "because that's how zombie processes are defined".Varicocele
"couldn't understand why zombie process are created here" That would be because you aren't calling wait() to read the child's exit status, and hence its entry is left behind in the process table.Coprolite
Thats ok. But when child runs for some time and exists there isnt any zombieBoomerang
Yeah — zombies are the living dead. Zombie processes have died (either from a signal or because they exited), and the parent process has not yet executed a wait() for the process. The zombie is dead, but still occupies a process table slot and will continue to do so until its parent waits for it, or the parent exits. If the parent exits, the child will be inherited by the init process (usually PID 1), and one of the main purposes of that process (if not the only one) is to wait for children to die.Lazuli
The child process executes the exit(0);, thus terminating. The parent process enters an infinite loop without waiting for its child to die. In this context, waiting means 'calls one of the functions wait() or waitpid(), or one of the various system-dependent alternatives such as wait3() or wait4()'. It doesn't just mean 'the parent goes on living'. When the child doesn't die, there is no possible zombie process; zombie processes are dead.Lazuli
A
30

In your code, zombie is created on exit(0) (comment with arrow below):

pid=fork();
if (pid==0) {
    exit(0);  // <--- zombie is created on here
} else {
    // some parent code ...
}

Why? Because you never waited on it. When something calls waitpid(pid), it returns postmortem information about process, like its exit code. Unfortunately, when process exited, kernel cannot just dispose of this process entry, or return code will be lost. So it waits for somebody to wait on it, and leaves this process entry around even if it does not really occupy any memory except for entry in process table - this is exactly what is called zombie.

You have few options to avoid creating zombies:

  1. Add waitpid() somewhere in the parent process. For example, doing this will help:

    pid=fork();
    if (pid==0) {
        exit(0);    
    } else {
        waitpid(pid);  // <--- this call reaps zombie
        // some parent code ...
    }
    
  2. Perform double fork() to obtain grandchild and exit in child while grandchild is still alive. Grandchildren will be automatically adopted by init if their parent (our child) dies, which means if grandchild dies, it will be automatically waited on by init. In other words, you need to do something like this:

    pid=fork();
    if (pid==0) {
        // child
        if (fork()==0) {
            // grandchild
            sleep(1); // sleep a bit to let child die first
            exit(0);  // grandchild exits, no zombie (adopted by init)
        }
        exit(0);      // child dies first
    } else {
         waitpid(pid);  // still need to wait on child to avoid it zombified
         // some parent code ...
    }
    
  3. Explicitly ignore SIGCHLD signal in parent. When child dies, parent gets sent SIGCHLD signal which lets it react on children death. You can call waitpid() upon receiving this signal, or you can install explicit ignore signal handler (using signal() or sigaction()), which will make sure that child does not become zombie. In other words, something like this:

    signal(SIGCHLD, SIG_IGN); // <-- ignore child fate, don't let it become zombie
    pid=fork();
    if (pid==0) {
        exit(0); // <--- zombie should NOT be created here
    } else {
         // some parent code ...
    }
    
Akan answered 23/4, 2013 at 10:35 Comment(2)
Why does ignoring SIGCHLD signal kill the zombie? I understand that it makes sure the child process doesn't become a zombie. So the not-zombie process will quit once the program quits? And a zombie process won't quit once a program quits?Votaw
Again, zombie cannot be killed: its already dead, all that remains is entry in kernel process table. Ignoring SIGCHLD lets kernel know that it's ok to dispose of that entry immediately.Akan

© 2022 - 2024 — McMap. All rights reserved.