回收子进程-孤儿进程、僵尸进城、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

相关文章

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Python实现自动化接收与处理手机验证码

《Python实现自动化接收与处理手机验证码》在移动互联网时代,短信验证码已成为身份验证、账号注册等环节的重要安全手段,本文将介绍如何利用Python实现验证码的自动接收,识别与转发,需要的可以参考下... 目录引言一、准备工作1.1 硬件与软件需求1.2 环境配置二、核心功能实现2.1 短信监听与获取2.

Python使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

一文带你深入了解Python中的GeneratorExit异常处理

《一文带你深入了解Python中的GeneratorExit异常处理》GeneratorExit是Python内置的异常,当生成器或协程被强制关闭时,Python解释器会向其发送这个异常,下面我们来看... 目录GeneratorExit:协程世界的死亡通知书什么是GeneratorExit实际中的问题案例

Linux中的进程间通信之匿名管道解读

《Linux中的进程间通信之匿名管道解读》:本文主要介绍Linux中的进程间通信之匿名管道解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基本概念二、管道1、温故知新2、实现方式3、匿名管道(一)管道中的四种情况(二)管道的特性总结一、基本概念我们知道多