106.进程控制(结束、孤儿、僵尸进程)以及进程回收

目录

结束进程

孤儿进程 

僵尸进程 

进程回收 

wait()

waitpid


        进程控制是指在操作系统中对进程进行创建、终止、挂起、唤醒以及进程之间的同步、通信等操作的管理。

结束进程

exit()_exit() 函数都用于终止一个进程,但它们之间有一些重要的区别:

exit() 函数:

  • 头文件: #include <stdlib.h>
  • 功能: exit() 函数用于正常终止程序的执行。它执行一系列清理操作,包括调用通过 atexit() 注册的终止处理程序,并将程序的返回状态传递给操作系统。
  • 清理操作: 会调用通过 atexit() 注册的终止处理程序,关闭文件流(通过 fclose()),刷新缓冲区等。
  • 使用范例:
    #include <stdlib.h>int main() {// 一些代码// 正常退出,返回状态码 0exit(0);
    }
    

    _exit() 函数:

  • 头文件: #include <unistd.h>
  • 功能: _exit() 函数也用于终止程序,但它是一个较低级别的函数。它不会执行 exit() 做的清理工作,包括不会调用通过 atexit() 注册的函数,不会刷新 I/O 缓冲区等。
  • 适用场景: _exit() 主要用于在子进程中立即终止程序而无需执行清理操作。在这种情况下,使用 _exit() 可以避免执行 exit() 中的一些不必要的操作。
  • 使用范例:
    #include <unistd.h>int main() {// 一些代码// 立即退出,不执行清理操作_exit(0);
    }
    

    在大多数情况下,如果你需要正常终止程序并执行清理操作,应该使用 exit() 函数。如果你希望在子进程中立即退出,可以使用 _exit()

孤儿进程 

        孤儿进程是指在其父进程结束或者被终止后,仍然在系统中运行的子进程。孤儿进程会被操作系统的 init 进程(进程号为1)接管,并由 init 进程负责回收。这确保了孤儿进程不会成为系统资源的泄漏。

        当一个进程创建了子进程,而父进程先于子进程结束,那么子进程就会变成孤儿进程。这通常发生在父进程创建子进程后,父进程先于子进程调用 exit() 终止,或者父进程意外崩溃的情况。

        init 进程会定期检查是否有孤儿进程,如果发现孤儿进程,就会成为孤儿进程的新的父进程,并负责回收它的资源。这种处理方式确保了操作系统的稳定性和资源管理的有效性。

下面是一个产生孤儿进程的简单示例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t child_pid = fork();if (child_pid < 0){// 错误处理perror("fork");exit(0);}if (child_pid > 0){// 父进程printf("我是父进程:pid=%d\n", getpid());exit(0);}else if (child_pid == 0){// 子进程sleep(2);printf("我是子进程:pid=%d,父进程:ID=%d\n", getpid(), getppid());}return 0;
}

        在 Linux 中,如果一个进程的父进程终止,而它还没有被领养,那么它会被 init 进程(PID=1)领养。这确保了孤儿进程总是有一个父进程。init 进程在系统启动时由内核启动,是所有进程的祖先。

        对于没有桌面环境的系统,确实是 init 进程接管孤儿进程。但是,对于有桌面环境的系统,具体情况可能有所不同,因为桌面环境通常有自己的进程管理机制。

僵尸进程 

        僵尸进程是已经结束执行的进程,但其在进程表中仍然保留着一定的信息,包括进程号(PID)和退出状态等。这样的进程称为僵尸进程。僵尸进程的存在可能导致系统中的进程表被占用,过多的僵尸进程可能影响系统的正常运行。

        通常,一个进程在结束时会向其父进程发送一个信号,告诉父进程它已经结束。父进程接收到这个信号后,应该调用 waitwaitpid 系统调用来获取子进程的退出状态,释放子进程的资源。如果父进程没有及时处理,子进程就会变成僵尸进程。

运行下面的代码就可以得到一个僵尸进程了:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t pid;// 创建子进程for (int i = 0; i < 5; ++i){pid = fork();if (pid == 0){break;}}// 父进程if (pid > 0){// 需要保证父进程一直在运行// 一直运行不退出, 并且也做回收, 就会出现僵尸进程while (1){printf("我是父进程, pid=%d\n", getpid());sleep(1);}}else if (pid == 0){// 子进程, 执行这句代码之后, 子进程退出了printf("我是子进程, pid=%d, 父进程ID: %d\n", getpid(), getppid());}return 0;
}

        这段代码创建了一个父进程和5个子进程。子进程在输出一行信息后立即退出,而父进程则进入一个无限循环,在每次循环中输出一行信息。

        在这个场景中,由于父进程一直在运行,而子进程在输出信息后就退出了,子进程就有可能成为僵尸进程。父进程没有调用 waitwaitpid 函数来回收子进程,因此子进程退出后,其退出状态信息会一直保留在进程表中,形成僵尸进程。

进程回收 

        为了避免僵尸进程的产生,一般我们会在父进程中进行子进程的资源回收,回收方式有两种,一种是阻塞方式wait(),一种是非阻塞方式waitpid()。

wait()

        这是个阻塞函数,如果没有子进程退出, 函数会一直阻塞等待, 当检测到子进程退出了, 该函数阻塞解除回收子进程资源。这个函数被调用一次, 只能回收一个子进程的资源,如果有多个子进程需要资源回收, 函数需要被调用多次。

函数原型如下:

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);

返回值:

  • 成功:返回被回收的子进程的进程ID
  • 失败: -1
  • 没有子进程资源可以回收了, 函数的阻塞会自动解除, 返回-1
  • 回收子进程资源的时候出现了异常
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>// wait 函数回收子进程资源
int main()
{pid_t pid;// 创建子进程for (int i = 0; i < 5; ++i){pid = fork();if (pid == 0){break;}}// 父进程if (pid > 0){// 需要保证父进程一直在运行while (1){// 回收子进程的资源// 子进程由多个, 需要循环回收子进程资源pid_t ret = wait(NULL);if (ret > 0){printf("成功回收了子进程资源, 子进程PID: %d\n", ret);}else{printf("回收失败, 或者是已经没有子进程了...\n");break;}printf("我是父进程, pid=%d\n", getpid());}}else if (pid == 0){// 子进程, 执行这句代码之后, 子进程退出了printf("我是子进程, pid=%d, 父进程ID: %d\n", getpid(), getppid());}return 0;
}

waitpid

        waitpid() 函数可以看做是 wait() 函数的升级版,通过该函数可以控制回收子进程资源的方式是阻塞还是非阻塞,另外还可以通过该函数进行精准打击,可以精确指定回收某个或者某一类或者是全部子进程资源。

#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
  • pid 参数指定要等待的子进程:

    • 如果 pid > 0,则等待进程ID等于 pid 的子进程。
    • 如果 pid == 0,则等待与调用进程在同一进程组的任一子进程。
    • 如果 pid == -1,则等待任一子进程,与 wait 效果相同。
    • 如果 pid < -1,则等待进程组ID等于 pid 绝对值的任一子进程。
  • status 是一个指向整型的指针,用于保存子进程的退出状态。

  • options 是一组位掩码,可以通过按位或运算来组合。常用的选项有:

    • WNOHANG:以非阻塞方式等待,即使没有子进程退出也立即返回。

返回值:

  • 如果函数是非阻塞的, 并且子进程还在运行, 返回0
  • 成功: 得到子进程的进程ID
  • 失败: -1
  • 没有子进程资源可以回收了, 函数如果是阻塞的, 阻塞会解除, 直接返回-1
  • 回收子进程资源的时候出现了异常
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>// 和wait() 行为一样, 阻塞
int main()
{pid_t pid;// 创建子进程for (int i = 0; i < 5; ++i){pid = fork();if (pid == 0){break;}}// 父进程if (pid > 0){// 需要保证父进程一直在运行while (1){// 回收子进程的资源// 子进程由多个, 需要循环回收子进程资源int status;pid_t ret = waitpid(-1, &status, 0); // == wait(NULL);if (ret > 0){printf("成功回收了子进程资源, 子进程PID: %d\n", ret);// 判断进程是不是正常退出if (WIFEXITED(status)){printf("子进程退出时候的状态码: %d\n", WEXITSTATUS(status));}if (WIFSIGNALED(status)){printf("子进程是被这个信号杀死的: %d\n", WTERMSIG(status));}}else{printf("回收失败, 或者是已经没有子进程了...\n");break;}printf("我是父进程, pid=%d\n", getpid());}}else if (pid == 0){// 子进程, 执行这句代码之后, 子进程退出了printf("===我是子进程, pid=%d, 父进程ID: %d\n", getpid(), getppid());}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/214082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新工科:数据科学与大数据技术实验中心解决方案,赋能高校新工科数智人才培养

随着数字经济蓬勃发展&#xff0c;数字化产业和产业数字化成为就业增长新动能。据人瑞人才与德勤调研显示&#xff0c;未来3年&#xff0c;数字产业化企业最需要运营人员和开发人员&#xff08;包括大数据开发工程师、数据建模开发工程师等&#xff09;&#xff0c;其次是数据分…

【RTOS学习】FreeRTOS中的链表 | 堆的管理

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f969;FreeRTOS中的链表&#x1f95e;初始化&#x1f95e;尾部插入&#x1f95e;按顺…

OpenWRT搭建本地web站点并结合内网穿透实现公网远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

【Windows】MCSM面板搭建Mycraft服务器,实现公网远程联机

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 前言 MCSManager是一个…

[香橙派]Orange pi zero 3命令行配网方法——建立ssh连接——Ubuntu配置WIFI自动连接

一、前言 前面我们给Orange Pi安装了Ubuntu系统&#xff0c;并通过MobaXterm进行了串口连接&#xff0c;但其实并不方便&#xff0c;在日常开发中&#xff0c;我们希望能够使用更方便的ssh连接来进行操作&#xff0c;因此配置网络是必要的。 本章介绍的方法无需网线、HDMI线等&…

upload-labs

01 随便上传个文件 发现对于上传类型有限制 查看页面代码发现是js的过滤直接关闭js 上传成功 右键图片在新建标签页打开文件 这里直接抓包改名字也行 02 抓包修改后缀名 03 发现后端做了检测抓包修改失败 大小写绕过失败&#xff0c;php特性php1等会被当成php执行 这里图片的…

MS1242,替代ADS1242,24bit 高精度、低功耗模数转换器

产品简述 MS1242/MS1243 是一款高精度、宽动态范围、 ∆-Σ 模数转 换芯片&#xff0c;其工作电压为 2.7V 至 5.25V &#xff0c;可以达到 24bit 无失码转 换&#xff0c;有效精度可达 21bit 。 MS1242/MS1243 可以广泛使用在工 业控制、称重、液体 / 气体化学分析、血液分…

手眼标定 - 最终精度和误差优化心得

手眼标定 - 标定误差优化项 一、TCP标定误差优化1、注意标定针摆放范围2、TCP标定时的点次态与工作姿态尽可能保持相近 二、深度相机对齐矩阵误差1、手动计算对齐矩阵 三、手眼标定拍照姿态1、TCP标定姿态优先2、水平放置棋盘格优先 为减少最终手眼标定的误差&#xff0c;可做或…

Get职场新知识:做分析,用大数据分析工具

为什么企业每天累积那么多的数据&#xff0c;也做数据分析&#xff0c;但最后决策还是靠经验&#xff1f;很大程度上是因为这些数据都被以不同的指标和存储方式放在各自的系统中&#xff0c;这就导致了数据的分析口径和标准不一致&#xff0c;无法在同一个分析软件上做综合分析…

Rsync+Sersync

服务器相关参数 源服务器 192.168.17.101 目标服务器&#xff08;同步到的服务器&#xff09; 192.168.17.103 ##目标服务器配置 ###1、配置rsync服务 1、安装rsync yum -y install rsync 2、配置rsync vim /etc/rsyncd.conf 配置文件内容 uid root gid root use c…

Module build failed : Error : Vue packages version mismatch:

Vue packages version mismatch: - vue2.7.15 (E:\Workspace_ce\erp\erp-web\node_modules\vue\dist\vue.runtime.common.js) - vue-template-compiler2.6.11 (E:\Workspace_ce\erp\erp-web\node_modules\vue-template-compiler\package.json) 【问题解决了&#xff0c;我很不…

bootstrap:选项卡功能DEMO

<!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>选项卡</title> <link rel"stylesheet" type"text/css" href"/cdn.bootcss.com/bootstrap/3.3.2/css/bootstrap.min.css" />…

记一次测试环境git翻车经历

本来想拉一个功能分支进行新的功能开发&#xff0c;合并代码发现没有冲突居然有文件被修改了&#xff0c;贸然选择最近的一次回滚提交&#xff0c;没想到不假思索的push -f 导致一部分dev主干的代码不见了。 事故记录 开发分支origin/dev&#xff0c;功能分支file 合并之后发…

Java 实现 文档 添加 水印 工具类

一、pom 文件引用 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>…

MeterSphere实战(一)

MeterSphere是一位朋友讲到的测试平台&#xff0c;说这东西是开源的&#xff0c;因为我是做测试的&#xff0c;很乐意了解一些新鲜事物。在我看来&#xff0c;测试就是要专注一些领域&#xff0c;然后要啥都会一点点&#xff0c;接着融会贯通起来&#xff0c;这样就可以万变不离…

C语言--不使用库函数,把一个数字转为字符串【详细解释】

一.题目描述 输入一个数字&#xff0c;把他转为字符串 比如&#xff1a;输入数字&#xff1a;12345 输出&#xff1a;12345&#xff08;这里的12345是字符串12345&#xff09; 二.思路分析 比如给定一个数字12345&#xff0c;先把它转为字符54321&#xff08;“54321”&#…

线程互斥与同步

用户级线程 内核的LWP Linux线程 OS概念中经常说的 用户级线程 和 内核级线程 也就是线程实现真的是在OS内部实现&#xff0c;还是应用层或用户层实现 很明显Linux是属于用户级线程 用户级执行流&#xff08;用户级线程&#xff09; &#xff1a;内核lwp 1 : 1 也有1&…

骁龙8 Gen 3 vs A17 Pro

骁龙8 Gen 3 vs A17 Pro——谁会更胜一筹&#xff1f; Geekbench、AnTuTu 和 3DMark 等基准测试在智能手机领域发挥着至关重要的作用。它们为制造商和手机爱好者提供了设备性能的客观衡量标准。这些测试有助于评估难以测量的无形方面。然而&#xff0c;值得注意的是&#xff0c…

骚操作:NanoDrop测蛋白浓度

​大家好&#xff0c;最近实验室的BCA仪器坏了&#xff0c;偶然发现nanodrop也可以测蛋白浓度&#xff0c;省不少时间&#xff01;本方法原理是&#xff1a;紫外吸收 友情提示&#xff1a;由于表格的存在&#xff0c;用电脑看本推文&#xff0c;效果更好 紫外吸收法 较为灵…

31条PCB设计布线技巧:

大家在做PCB设计时&#xff0c;都会发现布线这个环节必不可少&#xff0c;而且布线的合理性&#xff0c;也决定了PCB的美观度和其生产成本的高低&#xff0c;同时还能体现出电路性能和散热性能的好坏&#xff0c;以及是否可以让器件的性能达到最优等。 本篇内容&#xff0c;将…