Zombie and Orphan Processes in C
A process which has finished the execution but still has entry in the process table to report to its parent process is known as a zombie process. A child process always first becomes a zombie before being removed from the process table. The parent process reads the exit status of the child process which reaps off the child process entry from the process table.
In the following code, the child finishes its execution using exit() system call while the parent sleeps for 50 seconds, hence doesn’t call wait() and the child process’s entry still exists in the process table.
// A C program to demonstrate Zombie Process. // Child becomes Zombie as parent is sleeping // when child process exits. #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main() { // Fork returns process id // in parent process pid_t child_pid = fork(); // Parent process if (child_pid > 0) sleep(50); // Child process else exit(0); return 0; }
Note that the above code may not work with online compiler as fork() is disabled.
A process whose parent process no more exists i.e. either finished or terminated without waiting for its child process to terminate is called an orphan process.
// A C program to demonstrate Orphan Process. // Parent process finishes execution while the // child process is running. The child process // becomes orphan. #include<stdio.h> #include <sys/types.h> #include <unistd.h> int main() { // Create a child process int pid = fork(); if (pid > 0) printf("in parent process"); // Note that pid is 0 in child process // and negative if fork() fails else if (pid == 0) { sleep(30); printf("in child process"); } return 0; }
Zombie Processes and their Prevention
Prerequisites: fork() in C, Zombie Process
Zombie state : When a process is created in UNIX using fork() system call, the address space of the Parent process is replicated. If the parent process calls wait() system call, then the execution of parent is suspended until the child is terminated. At the termination of the child, a ‘SIGCHLD’ signal is generated which is delivered to the parent by the kernel. Parent, on receipt of ‘SIGCHLD’ reaps the status of the child from the process table. Even though, the child is terminated, there is an entry in the process table corresponding to the child where the status is stored. When parent collects the status, this entry is deleted. Thus, all the traces of the child process are removed from the system. If the parent decides not to wait for the child’s termination and it executes its subsequent task, then at the termination of the child, the exit status is not read. Hence, there remains an entry in the process table even after the termination of the child. This state of the child process is known as the Zombie state.
// A C program to demonstrate working of // fork() and process table entries. #include<stdio.h> #include<unistd.h> #include<sys/wait.h> #include<sys/types.h> int main() { int i; int pid = fork(); if (pid == 0) { for (i=0; i<20; i++) printf("I am Child\n"); } else { printf("I am Parent\n"); while(1); } }
Output : Now check the process table using the following command in the terminal $ ps -eaf Here the entry [a.out] defunct shows the zombie process.
Why do we need to prevent the creation of Zombie process?
There is one process table per system. The size of the process table is finite. If too many zombie processes are generated, then the process table will be full. That is, the system will not be able to generate any new process, then the system will come to a standstill. Hence, we need to prevent the creation of zombie processes.
Different ways in which creation of Zombie can be prevented
1. Using wait() system call : When the parent process calls wait(), after the creation of child, it indicates that, it will wait for the child to complete and it will reap the exit status of the child. The parent process is suspended(waits in a waiting queue) until the child is terminated. It must be understood that during this period, the parent process does nothing just waits.
// A C program to demonstrate working of // fork()/wait() and Zombie processes #include<stdio.h> #include<unistd.h> #include<sys/wait.h> #include<sys/types.h> int main() { int i; int pid = fork(); if (pid==0) { for (i=0; i<20; i++) printf("I am Child\n"); } else { wait(NULL); printf("I am Parent\n"); while(1); } }
2. By ignoring the SIGCHLD signal : When a child is terminated, a corresponding SIGCHLD signal is delivered to the parent, if we call the ‘signal(SIGCHLD,SIG_IGN)’, then the SIGCHLD signal is ignored by the system, and the child process entry is deleted from the process table. Thus, no zombie is created. However, in this case, the parent cannot know about the exit status of the child.
// A C program to demonstrate ignoring // SIGCHLD signal to prevent Zombie processes #include<stdio.h> #include<unistd.h> #include<sys/wait.h> #include<sys/types.h> int main() { int i; int pid = fork(); if (pid == 0) for (i=0; i<20; i++) printf("I am Child\n"); else { signal(SIGCHLD,SIG_IGN); printf("I am Parent\n"); while(1); } }
3. By using a signal handler : The parent process installs a signal handler for the SIGCHLD signal. The signal handler calls wait() system call within it. In this senario, when the child terminated, the SIGCHLD is delivered to the parent.On receipt of SIGCHLD, the corresponding handler is activated, which in turn calls the wait() system call. Hence, the parent collects the exit status almost immediately and the child entry in the process table is cleared. Thus no zombie is created.
// A C program to demonstrate handling of // SIGCHLD signal to prevent Zombie processes. #include<stdio.h> #include<unistd.h> #include<sys/wait.h> #include<sys/types.h> void func(int signum) { wait(NULL); } int main() { int i; int pid = fork(); if (pid == 0) for (i=0; i<20; i++) printf("I am Child\n"); else { signal(SIGCHLD, func); printf("I am Parent\n"); while(1); } }
Output : Here no any [a.out] defunct i.e. no any Zombie process is created.