孤儿进程和僵尸进程
本文讲述了什么是孤儿进程和僵尸进程,会带来怎样的问题以及如何处理
一、孤儿进程
1)什么是孤儿进程
孤儿进程,顾名思义,就是父进程提前终止,但是子进程还在运行中,父进程无法对子进程进行监管,子进程就成为了孤儿进程。
2)孤儿进程的危害
孤儿进程一般来讲,不会有什么危害,因为在一个进程成为孤儿进程后,init进程(PID = 1)会接管该进程,成为该进程的父进程,并且在该进程结束后回收其资源。
例如以下代码,子进程进入死循环,打印消息,父进程运行5s后退出,在父进程退出后,子进程变成孤儿进程,被init进程“收养”,通过对进程的监控信息可以验证这一结论。
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t id = fork();
//id为0,子进程
if(id == 0)
{
while(true)
{
sleep(1);
std::cout<<"this is child process"<<std::endl;
}
}
int cnt = 5;
while(cnt--)
{
sleep(1);
std::cout<<"this is father process"<<std::endl;
}
return 0;
}
二、僵尸进程
1)什么是僵尸进程
僵尸进程就是,子进程运行已经结束,但是父进程没有对其资源回收,导致子进程不能彻底退出,始终停留在Zombie状态。在僵尸状态,进程表中仍然会保留僵尸进程的PCB,占用系统资源。
2)僵尸进程的危害
僵尸进程会导致系统资源泄露,如果系统的PID已经耗尽,僵尸进程会导致操作系统无法创建新进程,同时大量的僵尸进程会拖慢系统运行速度。
int main()
{
pid_t id = fork();
//id为0,子进程
if(id == 0)
{
int cnt = 5;
while(cnt--)
{
sleep(1);
std::cout<<"this is child process"<<std::endl;
}
exit(1);
}
while(true)
{
sleep(1);
std::cout<<"this is father process";
}
return 0;
}
3)僵尸进程的避免方法
3.1)主动调用wait/waitpid
主动调用等待函数默认可以阻塞式地等待进程退出,waitpid也可以设置等待方式为WNOHANG从而实现非阻塞式等待,但是还是需要周期性检查子进程是否退出。
3.2)终止父进程
上面讲到过,父进程被提前终止,子进程会被init“收养”,成为孤儿进程,init进程会负责回收孤儿进程的资源,终止父进程的目的就是主动让子进程变成孤儿进程,让init为该子进程回收资源。
3.3)信号处理
在进程结束的时候,会向父进程发送SIGCHLD信号,可以在信号处理回调函数中,使用wait或者waitpid来回收资源,这样做的好处是,父进程不需要特定地等待子进程退出,而转而去执行自己的任务。还有一种方法,只在类unix系统下可用,将SIGCHLD的捕获手动设置为忽略,在收到该信号的时候,就会自动回收子进程的资源。