- 概念
- 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
- 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程控制块PCB仍然保存在系统中,这种进程称之为僵尸进程。
- 危害
如果父进程进程不调用wait / waitpid的话, 子进程退出后那么保留的pcb就不会释放,会一直被占用,但是系统所能使用的pcb是有限的,如果大量的产生僵死进程,系统可能产生不了新的进程。
孤儿进程会被init进程收养,退出后不会变成僵尸进程。
- 避免僵尸进程
(1)通过信号机制
子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示:
#include
#include
#include
#include
#include
static void sig_child(int signo);
int main()
{
pid_t pid;
signal(SIGCHLD,sig_child);
pid = fork();
if (pid < 0)
{
perror("fork error:");
exit(1);
}
else if (pid == 0)
{
printf("I am child process,pid id %d.I am exiting.
",getpid());
exit(0);
}
printf("I am father process.I will sleep two seconds
");
sleep(2);
system("ps -o pid,ppid,state,tty,command");
printf("father process is exiting.
");
return 0;
}
static void sig_child(int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) >0)
printf("child %d terminated.
", pid);
}
(2) fork 两次,将子进程变成孤儿进程
#include
#include
#include
#include
int main()
{
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("fork error:");
exit(1);
}
else if (pid == 0)
{
printf("I am the first child process.pid:%d ppid:%d
",getpid(),getppid());
pid = fork();
if (pid < 0)
{
perror("fork error:");
exit(1);
}
else if (pid >0)
{
printf("first procee is exited.
");
exit(0);
}
sleep(3);
printf("I am the second child process.pid: %d ppid:%d
",getpid(),getppid());
exit(0);
}
if (waitpid(pid, NULL, 0) != pid)
{
perror("waitepid error:");
exit(1);
}
exit(0);
return 0;
}