一、孤儿进程
1 #include<stdlib.h>
2 #include<unistd.h>
3 #include<stdio.h>
4 int main()
5 {
6 int n=0;
7 char *s = NULL;
8
9 pid_t id = fork();
10 if(id == -1)
11 {
12 exit(1);
13 }
14 if(id == 0)//在子进程中执行
15 {
16 n=3;
17 s = "child";
18 }
19 else//在父进程中执行
20 {
21 n = 7;
22 s = "parent";
23 }
24
25 int i =0;
26 for(;i<n;i++)//父子进程都可以执行
27 {
28 printf("s =%s,curr_pid= %d,curr_ppid = %d\n",s,getpid(),getppid());
29 sleep(3);
30
31 }
父进程执行7次,子进程执行3次,运行结果如下:
如果我们将父进程改为执行3次,子进程执行7次
1 #include<stdlib.h>
2 #include<unistd.h>
3 #include<stdio.h>
4 int main()
5 {
6 int n=0;
7 char *s = NULL;
8
9 pid_t id = fork();
10 if(id == -1)
11 {
12 exit(1);//0代表成功,1,2,3,,都是失败
13 }
14 if(id == 0)//在子进程中执行
15 {
16 n=7;
17 s = "child";
18 }
19 else
20 {
21 n = 3;
22 s = "parent";
23 }
24
25 int i =0;
26 for(;i<n;i++)//父子进程都可以执行
27 {
28 printf("s =%s,curr_pid= %d,curr_ppid = %d\n",s,getpid(),getppid());
29 sleep(3);
30
31 }
32 }
父进程肯定先执行完,
结果如下:
提示符出来的时候父进程执行完了,但子进程还没执行完。
因为运行的./main程序,也就是父进程,父进程执行完,命令提示符就会出现,等待下一个命令的输入,所以会出现上图情况,提示符出现了,子进程还没运行完,子进程继续输出。
上面运行程序时,父进程结束了,子进程还没结束,子进程就会变成孤儿进程。
孤儿进程会被一个固定的进程收养,一般是一号进程。
按约定,所以没有父进程的子进程都会被1号进程(也可以是其他进程,1号进程比较普遍)收养,1号进程成为子进程的父进程。
下图这个孤儿进程就是被1号进程收养
下图这个孤儿进程就不是被一号进程收养,而是1477号进程
1号进程就是系统启动后第一个创建出来的进程,init进程
二、进程结束过程
子进程结束后,exit (0)退出,占有的内存空间会被释放,进程实体会被删除,
exit (0); //退出码
0代表成功,其他数值代表不同类型的失败。
PCB中有专门的成员接收退出码 exit_code
系统要求父进程必须接收退出码,从而了解子进程的结束状态,成功还是失败。所以PCB在子进程运行结束时不会一起被删除,会保留到父进程获取了退出码才会被删除。
如果子进程结束前,父进程已经结束,子进程会被其他进程收养,这个进程会获取子进程的退出码。
三、僵死进程/僵尸进程
当子进程结束后,父进程还没有获取子进程的退出码,这时子进程被称为僵死进程/僵尸进程。此时的状态称为僵死状态。
若子进程还未结束,父进程已死亡,子进程会被1号进程 init 收养,再当子进程结束时时,init进程一定会获取子进程的退出码,子进程肯定不会变成僵死进程。
自己创建的进程可能会没有获取子进程的退出码,但init进程一定不会忘记获取。
1 #include<stdlib.h>
2 #include<unistd.h>
3 #include<stdio.h>
4 int main()
5 {
6 int n=0;
7 char *s = NULL;
8
9 pid_t id = fork();
10 if(id == -1)
11 {
12 exit(1);//0代表成功,1,2,3,,都是失败
13 }
14 if(id == 0)//在子进程中执行
15 {
16 n=3;
17 s = "child";
18 }
19 else
20 {
21 n = 7;
22 s = "parent";
23 }
24
25 int i =0;
26 for(;i<n;i++)//父子进程都可以执行
27 {
28 printf("s =%s,curr_pid= %d,curr_ppid = %d\n",s,getpid(),getppid());
29 sleep(3);
30
31 }
32 exit(0);
33 }
四、僵死进程及处理方法
僵死进程:子进程先于父进程结束,父进程没有调用wait 获取子进程退出码。
如何处理僵死进程:父进程通过调用wait()完成。
进程正常结束(exit之后)才会获得退出码
调用wait,
通过此接口 WIFEXITED(wstatus)可以判断程序是否正常结束(正常结束指可以运行到exit,而不是中途崩掉)。正常结束返回true,
通过接口 WEXITSTATUS(wstatus)可以获得退出码
1 #include<stdlib.h>
2 #include<unistd.h>
3 #include<stdio.h>
4 #include<sys/wait.h>
5 int main()
6 {
7 int n=0;
8 char *s = NULL;
9
10 pid_t id = fork();
11 if(id == -1)
12 {
13 exit(1);//0代表成功,1,2,3,,都是失败
14 }
15 if(id == 0)//在子进程中执行
16 {
17 n=3;
18 s = "child";
19 }
20 else
21 {
22 n = 7;
23 s = "parent";
24 int val = 0;//存储退出码
25 int child_pid = wait(&val);//获取子进程的退出码
26 if(WIFEXITED(val))//判断程序是否正常结束
27 {
28 printf("exit code :%d\n",WEXITSTATUS(val));//获得退出码
29 }
30 }
31
32 int i =0;
33 for(;i<n;i++)//父子进程都可以执行
34 {
35 printf("s =%s,curr_pid= %d,curr_ppid = %d\n",s,getpid(),getppid() );
36 sleep(3);
37
38 }
39 exit(3);//代表异常
40 }