孤儿进程
父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init
进程,则称init
进程领养孤儿进程。现在好像是用户进程中的system
进程。
僵尸进程
进程终止,父进程不进行回收,自己成残留资源(PCB)存放在内核中,变成僵尸进程。
子进程死亡以后会将自己占用的内存(4G)释放,但是会将死亡信息放在自己的PCB中,希望父进程调用得到子进程的死亡信息以后再清除PCB。需要注意的是僵尸进程是不能使用kill
命令清除掉的,因为kill
命令知识用来终止进程的,而僵尸进程已经终止。这就要求我们手动回收子进程。
这里的僵尸进程特别指的是父进程没有结束而子进程已经结束,如果父进程结束就算我们不手动回收也会自动回收(实际过程是父进程结束以后没有回收的子进程变成孤儿进程被init
进程或者system
进程回收)
wait函数回收子进程
一个进程在终止时会关闭所有的文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait
或者waitpid
获取这些信息,然后彻底清除这个进程。
shell下一个进程的退出状态可以用特殊变量$?
查看,因为shell
是他的父进程,当它终止时shell调用wait
或者waitpid
得到它的退出状态同时彻底清除掉这个进程。
wait函数可以回收子进程终止信息,该函数有三个功能:
- 阻塞等待子进程退出:如果子进程没有结束父进程不会干其他的事情
- 回收子进程残留的
PCB
资源 - 获取子进程结束状态(退出原因)
一次wait函数只能清除一个子进程
pid_t wait(int *status);
返回值:如果成功返回子进程ID,如果失败返回-1
(没有子进程的话就会报错)
status保存结束状态
- 进程正常结束
WIFEXITED(status) 为非0说明是正常退出
WEXITSTATUS(status)如果上面宏为真,使用这个宏获取进程退出状态(exit的参数)
- 进程异常终止(收到信号终止,例如段错误、总线错误、浮点数例外错误)
WIFSIGNALED(status) 为非0,说明程序异常终止
WTERMSIG(status)如果上面宏为真使用此宏 取得使得进程终止的那个信号的编号
- 进程处于暂停状态
WIFSTOPPED(status) 为非0,进程处于暂停状态
WSTOPSIG(status) 如果上述宏为真,取得使得进程暂停的那个信号的编号
WIFCONTINUED(status) 为真表示进程暂停后已经继续运行
waitpid函数
一次waitpid函数只能清除一个子进程,和wait
函数类似
pid_t waitpid(pid_t pid,int* status,int options)
第一个参数用于指定需要回收的进程ID,第三个参数可以设置不阻塞回收,即仅仅返回一个状态
pid
:
- 大于0 表示回收的子进程ID
- -1 表示回收任意子进程(相当于wait)
- 0 回收当前调用
waitpid
一个组的任意子进程,在一般情况下和-1
相同 - <-1 回收指定进程组内的任意子进程,
-进程组ID
,进程组ID可以用ps ajx
查看
options
: - 当参数为
WNOHANG
,非阻塞回收,轮询查看 - 当参数为
0
的时候,阻塞回收,相当于wait
返回值:
- 成功返回子进程ID
- 失败返回-1
- 如果轮询访问回收子进程的时候子进程没有结束则返回0
例如:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>int main(int argc, char* argv[])
{int n=5;if(argc>2){printf("too many arguments\n");exit(1);}else if(argc==2){n = atoi(argv[1]);}int pi;pid_t p,q;for(pi=0;pi<n;++pi){p=fork();if(0 == p){break;}else if(3 == pi){q = p;}}if(n==pi){printf("I am parent,pid = %d\n",getpid());//删除单个子进程//waitpid(q,NULL,0);//循环删除子进程//while(-1!=waitpid(-1,NULL,0));//非阻塞删除子进程pid_t tid;do{tid=waitpid(-1,NULL,WNOHANG);}while(tid != -1);printf("OK\n");while(1);}else{printf("I am child,pid = %d\n",getpid());}return 0;
}