问题
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?
回答1:
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 wait
ed 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:
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 ... }
Perform double
fork()
to obtain grandchild and exit in child while grandchild is still alive. Grandchildren will be automatically adopted byinit
if their parent (our child) dies, which means if grandchild dies, it will be automaticallywait
ed on byinit
. 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 ... }
Explicitly ignore SIGCHLD signal in parent. When child dies, parent gets sent
SIGCHLD
signal which lets it react on children death. You can callwaitpid()
upon receiving this signal, or you can install explicit ignore signal handler (usingsignal()
orsigaction()
), 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 ... }
来源:https://stackoverflow.com/questions/16078985/why-zombie-processes-exist