孤儿进程:
概念:若子进程的父进程已经死掉,而子进程还存活着,这个进程就成了孤儿进程。
为了保证每个进程都有一个父进程,孤儿进程会被init进程领养,init进程成为了孤儿进程的养父进程,当孤儿进程退出之后,由init进程完成对孤儿进程的回收。init进程的pid=1。
僵尸进程:
概念:子进程先退出,父进程没有完成对子进程资源的回收(父进程还没结束),此时子进程就变成了僵尸进程。
如何解决:
不能使用kill -9直接杀死僵尸进程,原因是僵尸进程是一个死掉的进程。
应该使用杀死僵尸进程父进程的方法来解决僵死进程;
原因是:杀死其父进程可以让init进程领养僵尸进程,最后由init进程回收僵尸进程(init进程回收已经结束的进程)。
wait函数:
函数原型: pid_t wait(int *wstatus);
函数作用:
- 阻塞并等待子进程退出。
- 回收子进程残留资源。
- 获取子进程结束状态(退出原因)
返回值:
- 成功:清理掉的子进程的pid
- 失败:-1(没有子进程)
wstatus参数:
1 WIFEXITED(wstatus):为非零->进程正常结束
WEXITSTATUS(wstatus):获取进程退出状态(return ...)
2 WIFSIGNALED(wstatus):为非零->进程异常结束(被信号杀死)
WTERMSIG(wstatus):取得进程终止的信号编号
结果:
waitpid函数:
函数原型: pid_t waitpid(pid_t pid, int *wstatus, int options);
函数参数:
pid:
< -1 meaning wait for any child process whose process group ID is
equal to the absolute value of pid.
-1 meaning wait for any child process.
0 meaning wait for any child process whose process group ID is
equal to that of the calling process at the time of the call to
waitpid().
> 0 meaning wait for the child whose process ID is equal to the
value of pid.
pid=-1 等待任一子进程。与wait等效。
pid>0 等待其进程id与pid相等的子进程。
options:设置为WNOHANG,函数为非阻塞,设置为0,函数阻塞。(阻塞的话父进程执行不了剩余的代码,除非子进程全部回收)
函数返回值:
>0:返回回收掉的子进程id
=-1:无子进程
=0:参数三为WNOHANG,且子进程正在运行。
使用:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/types.h>
5 #include<unistd.h>
6 #include <sys/wait.h>
7 int main()
8 {
9 //pid_t fork(void);
10 pid_t pid=fork();
11 if(pid<0)
12 {
13 perror("fork error");
14 return -1;
15 }
16 else if(pid==0)
17 {
18 printf("child:pid==[%d],fpid=[%d]\n",getpid(),getppid());
19 sleep(1);
20 return 33;
21 }
22 else if(pid>0)
23 {
24 printf("father:pid==[%d],fpid=[%d]\n",getpid(),getppid());
25 // pid_t wait(int *wstatus);
26 int wstatus;
27 // pid_t waitpid(pid_t pid, int *wstatus, int options);
28 while(1)
29 {
30 pid_t wpid=waitpid(-1,&wstatus,WNOHANG);
31 if(wpid>0)
32 {
33 printf("child:[%d] terminated\n",wpid);
34 if( WIFEXITED(wstatus))
35 {
36 printf("child normal exit,wstatus=[%d]\n",WEXITSTATUS(wstatus));
37
38 }
39 else if( WIFSIGNALED(wstatus))
40 {
41 printf("child killed by signal,signo=[%d]\n",WTERMSIG(wstatus));
42 }
43 }
44 else if(wpid==0)
45 {
46 printf("child is living\n");
47 }
48 else if(wpid=-1)
49 {
50 printf("no child is living\n");
51 break;
52 }
53 }
54 }
55 return 0;
56 }
因为我们使用了WNOHANG让waitpid处于不阻塞状态,我们可以使用while(1)让其陷入无限循环,wpid=0时说明子进程还没结束,wpid=-1时,已经不存在子进程,break退出循环。
结果:
wait和waitpid调用一次只能清理一个子进程