浅谈 Linux进程回收、wait、waitpid函数

文章目录

  • 前言
  • 进程回收
  • wait 函数
  • 进程回收 相关的宏函数介绍
  • waitpid 函数

前言

本文介绍 进程回收 的概念、相关宏函数、wait 函数 以及 waitpid 函数的使用方式。

进程回收

一个进程终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的 PCB 还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用 wait 或者 waitpid 获取这些信息,然后彻底清除掉这个进程,这就被称为 进程回收

wait 函数

wait 函数: 回收子进程残留的资源, 阻塞回收任意一个子进程,如果有多个子进程,哪个子进程先结束就回收哪个。

pid_t wait(int *status)
或者
pid_t wait(NULL)

参数:(status 是传出参数) 保存进程的状态。传入 NULL 表示父进程不关心子进程结束原因	返回值:成功: 回收的进程的 pid失败: -1, errno函数作用1:	阻塞等待子进程退出(子进程不结束就死等,一直等到子进程结束后收尸)函数作用2:	回收子进程残留资源(清理子进程残留在内核的 pcb 资源)函数作用3:	得到子进程结束状态。(这个 status 的值还需搭配宏函数使用,才能得到进程退出的原因)

NULL 作为参数没啥好说的,我们重点说说 status 这个参数。

前面说了,status 是一个传出参数,所谓传出参数,也就是说 wait 函数会在函数内部为 status 赋值,status 里保留的就是进程状态。我们单看这个 status 的值是没有意义的,这个值需要作为参数传入到宏函数里面,宏函数会根据传进来的 status 参数分析出进程结束的原因,所以 status 参数是给宏函数使用的。

进程回收 相关的宏函数介绍

宏函数是分析进程结束原因的,常用的宏函数有以下两类,需要头文件 #include <sys/wait.h>:

  • WIFEXITED(status) 为真,表示子进程正常终止 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。这个进程退出只也就是进程结束的原因。

  • WIFSIGNALED(status) 为真,表示子进程异常终止 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。

代码演示1:回收子进程,无需查明死亡原因

#include <stdio.h>
#include <unistd.h>/** 代码实现思路:* 创建子进程,让子进程sleep(10),* 父进程调用 wait 函数,获取 wait 的返回值,根据返回值判断是否回收成功**/int main() {int pid, wret;pid = fork();if(pid == 0) {printf("我是子进程 id: %d ,我正在 sleep...\n", getpid());sleep(10);printf("我是子进程 id: %d , 我先挂了\n", getpid());} else if(pid > 0) {printf("我是父进程, id: %d \n", getpid());wret = wait(NULL);  // 传入 NULL 表示不关心子进程死亡原因,也可以传入 &status ,但不会被用到if(wret == -1) {perror("子进程回收失败");}printf("成功回收子进程 %d\n", wret);}return 0;
}

在这里插入图片描述
通过以上输出,可以看到 wait 是阻塞的,父进程一直等到 wait 返回后才输出"成功回收子进程 xxx".

代码演示2:回收子进程,并查明进程结束原因

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>/** 代码实现思路:* 创建子进程,让子进程sleep(12),* 父进程调用 wait(&status) ,获取 wait 的返回值,根据返回值判断是否回收成功,* 再根据 status + 宏函数 的返回值,得出子进程结束的原因**/int main() {int pid, wret, status;pid = fork();if(pid == 0) {printf("我是子进程 id: %d ,我正在 sleep...\n", getpid());sleep(12);printf("我是子进程 id: %d , 我先挂了\n", getpid());return 153;} else if(pid > 0) {printf("我是父进程, id: %d \n", getpid());wret = wait(&status);if(wret == -1) {perror("子进程回收失败");exit(-1);}// 结合 status 和 宏函数 查明进程结束原因if(WIFEXITED(status)) {printf("子进程正常结束,退出值:%d\n", WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf("子进程异常结束,退出值:%d\n", WTERMSIG(status));}printf("我是父进程 %d,我已成功回收子进程 %d,并查明了结束原因。\n", getpid(), wret);}return 0;
}

在这里插入图片描述
以上结果很容易看出:
第一次执行后,子进程正常结束,退出码是153,153也就是子进程的结束原因。
第二次执行后,子进程被 kill -9 杀死,返回的是信号 9,这个信号 9 就是子进程的结束原因。

还有一点要说明的是 return 153,经过测试,这个返回值默认是0。
返回值的范围只能指定 0 - 255。

waitpid 函数

上面分析过 wait 函数,缺点很明显:

  1. 父进程阻塞回收子进程。
  2. 只能随机回收一个进程。

那么 waitpid 就是增强版了,waitpid 函数能以非阻塞的方式回收指定的任一子进程

需要注意,wait 或是 waitpid,一次都只能回收一个进程。

pid_t waitpid(pid_t pid, int *status, int options)

参数:pid:> 0: (传入进程 id) 指定回收某一个子进程-1:任意子进程,传入 -1 表示随便回收当前进程的一个子进程,谁先结束回收谁0:回收当前进程组中的所有子进程。status:(传出参数)被回收进程的状态,如果是 NULL,表示不关心子进程退出的原因。options:WNOHANG 指定回收方式为,非阻塞。如果使用 WNOHANG 选项并且没有已结束的子进程,waitpid() 将立即返回0,不会等待。如果有子进程已经终止,waitpid() 将返回该子进程的进程 ID。返回值:> 0 : 表示成功回收的子进程 pid0 : 函数调用时, 如果参3 是WNOHANG, 并且没有子进程结束,则返回0,回收不成功。-1: 失败。errno

代码演示:使用 waitpid 以非阻塞的方式回收进程

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>/** 所谓非阻塞,就是父进程调用 waitpid 后,继续执行后续语句,不必等到子进程结束。** 那么实现思路是这样的:*   创建子进程*   父进程调用 waitpid() ,获取 waitpid 的返回值,根据返回值判断是否回收成功,**   需要注意的是:fork 后,父子进程的执行顺序是随机的,父进程可能在子进程之前结束,所以要在父进程中sleep,等子进程先结束。*/int main() {int pid, wret;pid = fork();if(pid == 0) {printf("我是子进程 id: %d , 我先走一步\n", getpid());return 101;} else if(pid > 0) {// 防止父进程先于子进程结束导致回收失败,因为 waitpid 是非阻塞的sleep(2);// 该案例只是演示进程回收方式,不关系子进程结束原因,所以传入NULLwret = waitpid(-1, NULL, WNOHANG);  printf("我是父进程, id: %d,我已经执行 waitpid() \n", getpid());printf("我是父进程,id: %d ,我非阻塞地继续执行后续语句...\n", getpid());if(wret == -1) {perror("子进程回收失败");exit(-1);} else if(wret == 0) {  // 如果没在父进程中sleep,可能进入这个分支perror("回收失败,没有子进程结束。");exit(-1);}if(wret > 0) {printf("我是父进程 %d,我已成功回收子进程 %d \n", getpid(), wret);}}return 0;
}

在这里插入图片描述

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

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

相关文章

RocketMQ安装

mq服务端安装配置启动把windows做成服务 mq管理界面安装配置启动 mq服务端 安装 RocketMQ下载地址 配置 ROCKETMQ_HOME D:\google-d\rocketmq-all-5.2.0-bin-release启动 # bin目录cmd输入 start mqnamesrv.cmd把windows做成服务 http://t.csdnimg.cn/qd2RD mq管理界面 …

CentOS7设置虚拟机语言为中文

1.查看本地安装的语言 locale -a 是一个Linux命令&#xff0c;用于列出系统中可用的所有区域设置&#xff08;locales&#xff09;它包含了各种语言和地区的不同设置。 打开终端&#xff08;右键open terminal&#xff09;输入 locale -a 查看本地安装的语言&#xff1a; 其中z…

深入理解与应用工厂方法模式

文章目录 一、模式概述**二、适用场景****三、模式原理与实现****四、采用工厂方法模式的原因****五、优缺点分析****六、与抽象工厂模式的比较**总结 一、模式概述 ​ 工厂方法模式是一种经典的设计模式&#xff0c;它遵循面向对象的设计原则&#xff0c;特别是“开闭原则”&…

C语言-指针(上)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 本篇文章将为大家介绍C语言中的核心内容-指针&#xff0c;指针在C语言的中知识内容比…

详解 JavaScript 中的数组

详解 JavaScript 中的数组 创建数组 注&#xff1a;在JS中的数组不要求元素的类型&#xff0c;元素类型可以一样&#xff0c;也可以不一样 1.使用 new 关键字创建 let array new Array()2.使用字面量方式创建(常用) let array1 [1,2,3,"4"]获取数组元素 使用下…

Python 教学平台,支持“多班教学”的课程授课方式|ModelWhale 版本更新

龙行龘龘、前程朤朤&#xff0c;ModelWhale 新一轮的版本更新&#xff0c;期待为大家带来更优质的使用体验。 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; 新增 课程&#xff08;包括课件、作业、算力&#xff09;按班级管理&#xff08;团队版✓ …

Linux笔记-1

概述 简介 Linux是现在服务器上最常用的操作系统(OS - Operating system) - 所谓的操作系统本质上也是一个软件&#xff0c;是一个可以运行其他软件的容器如果一台服务器&#xff0c;没有安装操作系统&#xff0c;此时称之为裸机。裸机可以使用&#xff0c;在使用的时候需要使…

TCP与UDP基础

思维导图&#xff1a; TCP&#xff1a; 服务器 #include<myhead.h> #define SER_IP "192.168.252.163" #define SER_PORT 6666 int main(int argc, const char *argv[]) {//&#xff11;、创建用于监听的套接字int sfd-1;sfdsocket(AF_INET,SOCK_STREAM,0);/…

泰迪智能科技企业数据挖掘平台使用场景

企业数据挖掘平台助力企业数据挖掘&#xff0c;数据挖掘平台也在多个领域发挥着重要的作用。 企业数据挖掘平台具有数据抓取、数据清洗、数据分析、机器学习等多项功能&#xff0c;广泛应用于企业的各个领域&#xff0c;包括&#xff1a;金融行业、医疗行业、交通领域、教育、制…

Java对象大小计算

概述 在实际应用中&#xff0c;尤其是在进行JVM调优时&#xff0c;理解并正确估计对象大小是非常重要的&#xff0c;因为这直接影响到内存分配、垃圾回收效率以及应用程序的整体性能。 对象的组成 在Java中&#xff0c;计算一个对象的大小是为了了解它在内存中占用的确切空间…

【洛谷 P9240】[蓝桥杯 2023 省 B] 冶炼金属 题解(二分答案)

[蓝桥杯 2023 省 B] 冶炼金属 题目描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V V V&#xff0c; V V V 是一个正整数&#xff0c;这意味着消耗 V V V 个普通金属 O 恰好可以冶炼出一个特殊金属 X&#xff0c;当普…

聊聊 HTTP 性能优化

作为用户的我们在 "上网冲浪" 的时候总是希望快一点&#xff0c;尤其是抢演唱会门票的时候&#xff0c;但是现实并非如此&#xff0c;有时候我们会遇到页面加载缓慢、响应延迟的情况。 而 HTTP 协议作为互联网世界的基础&#xff0c;从网站打开速度到移动应用的响应…