孤儿进程和僵尸进程的概念
-
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,此时init进程变成子进程的父进程,称为init进程领养孤儿进程。
-
僵尸进程:进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程
NOTE:僵尸进程不能使用kill命令清除,因为kill命令只是用来终止进程的,而僵尸进程已经终止。当父进程也死了,僵尸进程交给init进程解决了。
wait函数
- pid_t wait(int *status); 成功:清理掉的子进程ID;失败:-1 (无子进程)
一次调用只回收一个子进程,回收多个子进程:while(wait(NULL));
- 当进程终止时,操作系统的隐式回收机制会:
(1) 关闭所有文件描述符
(2) 释放用户空间分配的内存
(3) 内核中PCB仍存在,其中保存该进程的退出状态。(正常终止→退出值;异常终止→终止信号)
- 父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:
① 阻塞等待子进程退出
② 回收子进程残留资源
③ 获取子进程结束状态(退出原因)。
- 可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。宏函数可分为如下三组:
(1)WIFEXITED(status) 为非0 → 进程正常结束
WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
child_pid = wait(&status);
if(wpid>0)//子进程的PID应该 >0
{
if(WIFEXITED(status))
{
printf("exit value is %d \n",WEXITSTATUS(status)); //子进程退出时的值x:exit(x) or return(x)
}
}
(2)WIFSIGNALED(status) 为非0 → 进程异常终止
WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
wpid = wait(&status);
if(wpid>0)
{
if(WIFSIGNALED(status))
printf("signal value is %d \n",WTERMSIG(status));
}
如果子进程执行了 100/0的算术运算,父进程输出8,用kill -l 命令查看,则异常信号编号为8是SIGFPE,
(*3)WIFSTOPPED(status) 为非0 → 进程处于暂停状态( 拓展 )
WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
waitpid函数
- 作用同wait,但可指定pid进程清理,可以不阻塞
- pid_t waitpid(pid_t pid, int *status, in options); 成功:返回清理掉的子进程ID;失败:-1( 无子进程)
参数 pid:> 0 回收指定ID的子进程
-1 回收任意子进程(相当于wait)
0 回收和当前调用waitpid一个组的所有子进程
< -1 回收指定进程组内的任意子进程
参数options:为WNOHANG,且子进程正在运行。返回0
:为0 ,且子进程正在运行。一直阻塞等待
例子1:父进程循环创建5个进程,只回收第3个进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
int i=0,wpid;
printf("------------------------\n");
for(i=0;i<5;i++)
{
pid=fork();
if(pid<0)
{
perror("fork error");
}
else if(pid == 0)
{
break;
}
else
{
if(i==3)
wpid=pid;
}
}
sleep(i);
if(i<5)
{
printf("i am %dth child,my pid is %d\n",i,getpid());
}
if(i==5)
{
waitpid(wpid,NULL,0);
printf("i am father ,my pid is %d\n",getpid());
while(1); //父进程停在这,
}
return 0;
}
左边:执行结果 右边:ps-aux 命令查看的进程
例子2:父进程回收全部进程
if(i==5)
{
while(waitpid(-1,NULL,0)>0); //循环回收,当没有子进程回收,返回-1,跳出
printf("i am father ,my pid is %d\n",getpid());
while(1); //父进程停在这,
}
结果:只剩下父进程,子进程全部回收了,没有僵尸进程了