Sunday, December 13, 2009

double fork to avoid zombie process

It is a common mistake to fork a child process without calling waitpid() to wait for the termination of the child process. Without a wait() call, the child process will become a zombie process after its termination because its parent process does not cleanup its process information in the system. A zombie process occupies a pid in the system, decrease the available pids in the system. Zombies are mark as "defunct" if you check the process by the "ps" command.

However, sometimes we do not want the parent process to wait for its child process for a long time. There is a way to achieve both "not create zombie process" and "not wait for the child process to its termination", and the way is to do a double fork.

The idea is simple, when a parent process (say A) want to fork a child process to do "something". Process A does not fork a process to do "something" directly. Process A first forks a child process (say B), and process then forks its child process (say C) to do "something" and process B terminates as soon as process C is created. In this way, process A only has to wait for process B for a short time. In the same time, since it has no parent process (process B is dead), the system will "rechild" process C to the init process. The init process calls wait() for its child process, solving the zombie process problem.

The program looks like


void func()
{
pit_t pid1;
pit_t pid2;
int status;

if (pid1 = fork()) {
/* parent process A */
waitpid(pid1, &status, NULL);
} else if (!pit1) {
/* child process B */
if (pid2 = fork()) {
exit(0);
} else if (!pid2) {
/* child process C */
execvp("something");
} else {
/* error */
}
} else {
/* error */
}
}

15 comments:

Anzor said...

it's the best explanation I've ever read. i knew i had to use double fork, but i didn't get why. thanx

GiLoITAGe said...

Thank you for your explanation. I've used this solution in an project and it worked well (also if it has an expensive overhead). If you don't want manage signals, this is the best way i think..

Siddharth Rao said...
This comment has been removed by the author.
darren2000 said...

In my case, I catch signal SIGCHLD and then perform wait(). Give you as reference.

Zac Hansen said...

pit_t should be pid_t

riko saputra said...

good references when I visited to get good information

Mengobati Asam Urat

Kushi Rao said...

Thanks a lot..... :) :) :)

Karthik Jain said...

Thanks for the explanation. I'll use this solution in my project.

Nedo said...

Thank you it works perfectly!

Iain Fraser said...

Nice tutorial, but there are some bugs in your code.

Firstly it should be pid_t.

But more importantly the if,else if,else statement will never reach else.

When fork fails you get -1, -1 is true in C. So your error handling does not work.

Thanks for the article though

Funmungus Sugnumnuf said...

Thank you, just what I needed. I added a `signal ( SIGHUP, SIG_IGN ) ;` in the grandchild for good measure.

Majid Nik said...

Nice Explanation... Thank you

Vikram Bharadwaj said...

MH Chen
Thank you for this explanation!

Adarsh Trivedi said...

Best explanation I have found on Internet for this. Thank You.

John Youi said...

Why not A just died let the B being adopted by system?