回收子进程-孤儿进程、僵尸进城、wait()、怎么处理僵死进程

2024-02-02 16:48

本文主要是介绍回收子进程-孤儿进程、僵尸进城、wait()、怎么处理僵死进程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

孤儿进程:

父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init 进程领养孤儿进程。

僵尸进程:

进程终止,父进程尚未挥手,子进程残留资源PCB存放于内核中,编程僵尸进程;

  • 值得注意的是,僵尸进程不能使用kill()命令杀死,kill是终结一个进程的,而僵死进程是出现在进程终止后出现的;

wait():

虽然子进程调用函数execve()之后拥有自己的内存空间,称为一个真正的进程,但由于子进程毕竟由父进程所创建,所以按照计算机技术中谁创建谁负责销毁的惯例,父进程需要在子进程结束之后释放子进程所占用的系统资源。

为实现上述目标,当子进程运行结束后,系统会向该子进程的父进程发出一个信息,请求父进程释放子进程所占用的系统资源。但是,父进程并没有准确的把握一定结束于子进程结束之后,那么为了保证完成为子进程释放资源的任务,父进程应该调用系统调用wait()。

如果一个进程调用了系统调用wait(),那么进程就立即进入等待状态(也叫阻塞状态),一直等到系统为本进程发送一个消息。在处理父进程与子进程的关系上,那就是在等待某个子进程已经退出的信息;如果父进程得到了这个信息,父进程就会在处理子进程的“后事”之后才会继续运行。

也就是说,wait()函数功能是:父进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

如果父进程先于子进程结束进程,则子进程会因为失去父进程而成为“孤儿进程”。在Linux中,如果一个进程变成了“孤儿进程”,那么这个进程将以系统在初始化时创建的init进程为父进程。也就是说,Linux中的所有“孤儿进程”以init进程为“养父”,init进程负责将“孤儿进程”结束后的资源释放任务。

Linix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放。 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

大家可以看看这篇博客对僵死进程和孤儿进程的理解:https://www.cnblogs.com/Anker/p/3271773.html

父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:

  • 阻塞等待子进程退出

  • 回收子进程残留资源

  • 获取子进程结束状态(退出原因)。

头文件

 #include <sys/types.h>#include <sys/wait.h>

函数实现

   pid_t wait(int *status);//成功:清理掉的子进程ID;失败: -1 (没有子进程)pid_t waitpid(pid_t pid, int *status, int options);int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

僵尸进程解决办法

(1)通过信号机制

子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示:

  • 对信号的相应方式为:SIG_DFL默认、SIG_IGN忽略、fun自定义
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>static void sig_child(int signo);int main()
{pid_t pid;//创建捕捉子进程退出信号signal(SIGCHLD,sig_child);pid = fork();if (pid < 0){perror("fork error:");exit(1);}else if (pid == 0){printf("I am child process,pid id %d.I am exiting.\n",getpid());exit(0);}printf("I am father process.I will sleep two seconds\n");//等待子进程先退出sleep(2);//输出进程信息system("ps -o pid,ppid,state,tty,command");printf("father process is exiting.\n");return 0;
}static void sig_child(int signo)
{pid_t  pid;int   stat;//处理僵尸进程while ((pid = waitpid(-1, &stat, WNOHANG)) >0)printf("child %d terminated.\n", pid);
}

(2)fork两次
  原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。测试程序如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>int main()
{pid_t  pid;//创建第一个子进程pid = fork();if (pid < 0){perror("fork error:");exit(1);}//第一个子进程else if (pid == 0){//子进程再创建子进程printf("I am the first child process.pid:%d\tppid:%d\n",getpid(),getppid());pid = fork();if (pid < 0){perror("fork error:");exit(1);}//第一个子进程退出else if (pid >0){printf("first procee is exited.\n");exit(0);}//第二个子进程//睡眠3s保证第一个子进程退出,这样第二个子进程的父亲就是init进程里sleep(3);printf("I am the second child process.pid: %d\tppid:%d\n",getpid(),getppid());exit(0);}//父进程处理第一个子进程退出if (waitpid(pid, NULL, 0) != pid){perror("waitepid error:");exit(1);}exit(0);return 0;
}

这篇关于回收子进程-孤儿进程、僵尸进城、wait()、怎么处理僵死进程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/671346

相关文章

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

MySql死锁怎么排查的方法实现

《MySql死锁怎么排查的方法实现》本文主要介绍了MySql死锁怎么排查的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录前言一、死锁排查方法1. 查看死锁日志方法 1:启用死锁日志输出方法 2:检查 mysql 错误

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Linux环境变量&&进程地址空间详解

《Linux环境变量&&进程地址空间详解》本文介绍了Linux环境变量、命令行参数、进程地址空间以及Linux内核进程调度队列的相关知识,环境变量是系统运行环境的参数,命令行参数用于传递给程序的参数,... 目录一、初步认识环境变量1.1常见的环境变量1.2环境变量的基本概念二、命令行参数2.1通过命令编程

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Rsnapshot怎么用? 基于Rsync的强大Linux备份工具使用指南

《Rsnapshot怎么用?基于Rsync的强大Linux备份工具使用指南》Rsnapshot不仅可以备份本地文件,还能通过SSH备份远程文件,接下来详细介绍如何安装、配置和使用Rsnaps... Rsnapshot 是一款开源的文件系统快照工具。它结合了 Rsync 和 SSH 的能力,可以帮助你在 li

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed

Redis如何使用zset处理排行榜和计数问题

《Redis如何使用zset处理排行榜和计数问题》Redis的ZSET数据结构非常适合处理排行榜和计数问题,它可以在高并发的点赞业务中高效地管理点赞的排名,并且由于ZSET的排序特性,可以轻松实现根据... 目录Redis使用zset处理排行榜和计数业务逻辑ZSET 数据结构优化高并发的点赞操作ZSET 结

微服务架构之使用RabbitMQ进行异步处理方式

《微服务架构之使用RabbitMQ进行异步处理方式》本文介绍了RabbitMQ的基本概念、异步调用处理逻辑、RabbitMQ的基本使用方法以及在SpringBoot项目中使用RabbitMQ解决高并发... 目录一.什么是RabbitMQ?二.异步调用处理逻辑:三.RabbitMQ的基本使用1.安装2.架构