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

时间:2023-12-30 11:45:14

23.1 进程链和进程扇

23.1.1 概念

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

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

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

23.1.2 进程链的构建

  process_link.c

 /* 创建5个进程(包括父进程) */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(int argc, char *argv[])
{
int counter = ; if(argc < ) {
counter = ;
} else {
counter = atoi(argv[]);
} int i = ;
pid_t pid; //循环变量从1开始,要减去父进程,即创建4个子进程
//需要保证父进程要跳出循环,子进程去创建子子进程
for(; i < counter; i++) {
pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid > ) {
break; //父进程退出循环,子进程继续做循环
}
} printf("pid : %d, ppid: %d\n", getpid(), getppid());
while() {
sleep();
} return ;
}

  运行:

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

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

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

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

23.1.3 进程扇的构建

 /* 创建5个进程(包括父进程) */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(int argc, char *argv[])
{
int counter = ; if(argc < ) {
counter = ;
} else {
counter = atoi(argv[]);
} int i = ;
pid_t pid; //循环变量从1开始,要减去父进程,即创建4个子进程
//需要保证父进程要跳出循环,子进程去创建子子进程
for(; i < counter; i++) {
pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid == ) {
break; //子进程退出循环,父进程继续做循环
}
} printf("pid : %d, ppid: %d\n", getpid(), getppid());
while() {
sleep();
} return ;
}

  编译运行如下,

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

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

23.2 守护进程和孤儿进程

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

23.2.1 守护进程

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

23.2.2 孤儿进程

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

  process_orphen.c

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(void)
{
pid_t pid; pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid > ) {
printf("%d deaded\n", getpid());
exit();
} else {
sleep();
printf("pid : %d, ppid : %d\n", getpid(), getppid());
} return ;
}

  编译运行:

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

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

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

  这个进程的作用是:用于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

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(void)
{
pid_t pid; pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid == ) {
printf("pid : %d, ppid: %d\n", getpid(), getppid());
exit(); //子进程结束成为僵尸进程
} while() {//父进程继续循环
sleep();
} exit();
}

  编译运行:

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

  另开一终端,查看进程

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

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

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