二十三、Linux 进程与信号---进程链和进程扇、守护进程和孤儿进程以及僵尸进程

23.1 进程链和进程扇

23.1.1 概念

  进程链:一个父进程构建出一个子进程,子进程再构建出子子进程,子子进程构建出子子子进程。。。。 这种就为进程链

  进程扇:一个父进程构建出多个子进程,子进程都是由同一个父进程构建出来

  

23.1.2 进程链的构建

  process_link.c

 1 /* 创建5个进程(包括父进程) */
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 
 6 int main(int argc, char *argv[])
 7 {
 8     int counter = 0;
 9 
10     if(argc < 2) {
11         counter = 2;
12     } else {
13         counter = atoi(argv[1]);
14     }
15 
16     int i = 1;
17     pid_t pid;
18 
19     //循环变量从1开始,要减去父进程,即创建4个子进程
20     //需要保证父进程要跳出循环,子进程去创建子子进程
21     for(; i < counter; i++) {
22         pid = fork();
23         if(pid < 0) {
24             perror("fork error");
25             exit(1);
26         } else if(pid > 0) {
27             break;    //父进程退出循环,子进程继续做循环
28         }
29     }
30 
31     printf("pid : %d, ppid: %d\n", getpid(), getppid());
32     while(1) {
33         sleep(1);
34     }
35 
36     return 0;
37 }

  运行:

  

  执行 ps -ef | grep process_link 查看进程:

  

  注意 8468 进程编号并不是 process_link 进程,它为 shell 的进程,运行的 process_link 的进程的父进程就是shell终端

23.1.3 进程扇的构建

 1 /* 创建5个进程(包括父进程) */
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 
 6 int main(int argc, char *argv[])
 7 {
 8     int counter = 0;
 9 
10     if(argc < 2) {
11         counter = 2;
12     } else {
13         counter = atoi(argv[1]);
14     }
15 
16     int i = 1;
17     pid_t pid;
18 
19     //循环变量从1开始,要减去父进程,即创建4个子进程
20     //需要保证父进程要跳出循环,子进程去创建子子进程
21     for(; i < counter; i++) {
22         pid = fork();
23         if(pid < 0) {
24             perror("fork error");
25             exit(1);
26         } else if(pid == 0) {
27             break;    //子进程退出循环,父进程继续做循环
28         }
29     }
30 
31     printf("pid : %d, ppid: %d\n", getpid(), getppid());
32     while(1) {
33         sleep(1);
34     }
35 
36     return 0;
37 }

  编译运行如下,

  

  子进程对应的父进程都为 113892

23.2 守护进程和孤儿进程

  进程在操作系统中根据功能分为各种各样的进程。

23.2.1 守护进程

  • 守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,在系统关闭时终止。
  • 所有守护进程都以超级用户(用户 ID 为0)的优先权运行
  • 守护进程没有控制终端
  • 守护进程的父进程都是 init 进程

23.2.2 孤儿进程

  • 父进程结束,子进程就成为孤儿进程,会由 1 号进程(init 进程)领养

  process_orphen.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 
 5 int main(void)
 6 {
 7     pid_t pid;
 8 
 9     pid = fork();
10     if(pid < 0) {
11         perror("fork error");
12         exit(1);
13     } else if(pid > 0) {
14         printf("%d deaded\n", getpid());
15         exit(0);
16     } else {
17         sleep(4);
18         printf("pid : %d, ppid : %d\n", getpid(), getppid());
19     }
20 
21     return 0;
22 }

  编译运行:

  

  这里由些奇怪的地方是孤儿进程被进程 2323领养,查看下这个进程:

  

  这个进程的作用是:用于linux开机自动启动某些后台服务,同时还承担监控这些服务运行状态的功能。

  这个进程代替了 1 号进程的一些特性,如果作死想试下关闭掉这个进程,可以进入下面的链接尝试:

  https://www.cnblogs.com/chilumanxi/p/5136102.html

23.2.3 僵尸进程

  • 子进程结束,但是没有完全释放内存(在内核中的  task_struct 没有释放),该进程就成为僵尸进程。
  • 当僵尸进程的父进程结束后,就会被 init 进程领养,最终被回收
  • 避免僵尸进程
    • 让僵尸进程的父进程来回收,父进程每隔一段时间来查询子进程是否结束并回收,调用 wait() 或者 waitpid() ,通知内核释放僵尸进程
    • 采用信号 SIGCHLD 通知处理,并在信号处理程序中调用 wait 函数
    • 让僵尸进程成为孤儿进程,由 init 进程回收

(1)构建僵尸进程

  process_zombie.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 
 5 int main(void)
 6 {
 7     pid_t pid;
 8 
 9     pid = fork();
10     if(pid < 0) {
11         perror("fork error");
12         exit(1);
13     } else if(pid == 0) {
14         printf("pid : %d, ppid: %d\n", getpid(), getppid());
15         exit(0); //子进程结束成为僵尸进程
16     }
17 
18     while(1) {//父进程继续循环
19         sleep(1);
20     }
21 
22     exit(0);
23 }

  编译运行:

  

  另开一终端,查看进程

  114707 为父进程,为S+,即可中断运行状态

  子进程为 114708,状态为 Z+,Z即代表是僵尸进程,或者看进程名的 defunct ,有这个名字也为僵尸进程

猜你喜欢

转载自www.cnblogs.com/kele-dad/p/9142206.html