当前位置: 首页 > article >正文

【Linux】进程控制-----进程等待wait与waitpid

目录

一、进程为什么要等待:

二、父进程是如何做到进程等待的:

单进程等待:

多进程的等待:

waitpid介绍:

非阻塞轮询:


一、进程为什么要等待:

前面我们了解到,当子进程退出的时候,父进程不读取子进程的退出状态,子进程就会成为僵尸进程,造成内存泄漏的问题

1、回收僵尸进程:
当一个进程成为僵尸进程的时候,这个僵尸进程是无法被kill -9杀死的,这个时候就需要这个僵尸进程的父进程给他“善终”,就是父进程需要调用wait或者waitpid确认子进程的退出信息以回收僵尸进程的资源以防止内存泄漏

2、获取子进程的退出情况:
知道子进程的退出情况就能够知道,父进程给子进程的任务完成得怎么样了

注意:
父进程通过函数等待子进程运行结束,此时父进程属于阻塞状态

进程等待是什么:
父进程通过系统调用wait、waitpid来对子进程进行状态检测与回收的功能

二、父进程是如何做到进程等待的:

在父进程的代码中有fork函数创建代码,那么也有waitwaitpid函数进行系统调用等待子进程

可以在man手册中查看这两个函数所在的库函数和形参:

可以看到:
wait比waitpid函数要少两个形参,所以wait是waitpid的子集,waitpid比wait使用得更多,因为waitpid提供了更多的灵活性和功能

返回值:

等待成功时,返回 >0 的值
等待失败时,返回 -1
等待中,返回 0

waitpid中的形参含义:

pid表示所等子进程的pid
status为整型,在低16位中 次低8位表示退出码,第7位表示core dump标志,低7位表示终止信号
这是一个输出型参数,获取子进程的退出状态,不关心可设置为NULL(在后面会展开讲)
options是指定等待子进程的方式,包括阻塞和非阻塞等待

单进程等待:

如下:
思路就是在父进程中创建一个代码,在id == 0的代码块中执行子进程的代码,在id>0的代码块中执行父进程的代码块并且等待子进程

在上述代码中分为三个阶段:
第一个阶段是创建阶段,父进程创建5个子进程,每个子进程运行5秒
第二个阶段是父进程继续运行它自己的代码,此时子进程变为僵尸进程
第三个阶段就是父进程等到了子进程,等待成功后僵尸进程所占用的资源就会被释放

第一个阶段

第二个阶段

第三个阶段:

多进程的等待:

如上是使用wait进行等待的,wait一次是只等待一个随机的进程,

如上的代码就是首先父进程创建5个子进程,然后等到子进程运行后,结束进程变成僵尸进程,在等待5秒这些僵尸进程依次由父进程调用wait进行资源回收,

创建进程:

进程结束,还没有被父进程等到,变成僵尸进程

父进程依次等待子进程,回收僵尸进程

注意:
倘若子进程一直进行循环运行,没有退出,那么父进程也不会退出,它会一直等待子进程的返回,此时父进程就叫做阻塞等待,父进程会一直阻塞在wait()调用处,直到子进程结束,这意味着父进程在子进程结束之前不会继续执行其他任务

waitpid介绍:

返回值:
等待成功,waitpid是返回收集到的子进程的pid
等待失败:父进程只能等待自己的子进程,如果等待的不是自己的子进程就会等待失败,返回-1
如果设置了WNOHANG,而调用waitpid发现没有已退出的子进程可收集,则返回0

pid就是父进程中正在等待子进程的pid,也可以传-1,表示随机等待子进程,这就和wait一样了

status
这是一个表示状态的整型,但是不能认为这个是一个整型,这是一个输出型参数,能够将函数内部的数据通过status带出来,

总体可以看做位图,这个整型有32个比特位,其中高16位这里不使用,不需要管,只关注低16位,其中低16位又分三部分:

拿到退出码和退出信号:

exitCode = (status >> 8) & 0xFF; //退出码
exitSignal = status & 0x7F;      //退出信号

在按位与运算中,只有当两个相应的二进制位都为1时,结果位才为1,否则为0,

拿到退出码的思路:首先把这个二进程整体向右移8个比特位,然后就拿到次低8位,这些就是表示正常退出时的退出码,然后将拿到的值按位与上二进制中的八个一,也就是十六进制中的0xFF,这样就可以拿到退出码了

拿到退出信号的思路:将status直接按位与上七个1,左边的都是0,这样就可以拿到异常终止时的终止信号了

但是我们不用这么麻烦,系统中已经给了我们两个宏来直接拿到退出码,和检查进程是否正常退出
WEXITSTATUS(status):用于获取进程的退出码
WIFEXITED(status):用于查看进程是否是正常退出,本质是检查是否收到信号

当子进程正常终止时,WIFEXITED‌会返回一个非零值,表示子进程已经退出
否则,它将返回零,表示子进程尚未退 出或终止出错‌

上述两个宏本质上还是使用的是位运算

注意:
当一个进程异常退出时,说明该进程是被信号所杀,那么该进程的退出码也就没有意义了

如下:

最开始创建一个子进程,然后进行判断,若id < 0 则证明进程创建失败,

在id == 0的代码块是子进程所执行的,子进程运行了五秒后正常退出,退出码为0

在id > 0的代码块中是父进程所执行的,父进程运行了10秒多一点,前五秒和子进程一起运行,在后五秒就是子进程结束成为僵尸进程,父进程依然在运行,

等到父进程的while循环完后,等待子进程,回收子进程的资源,

若等待后的返回值是等于子进程的id就证明返回成功,然后就可以通过两个宏看看子进程是正常退出还是异常退出,如果ret为-1就证明等待失败(比如父进程等待的不是它自己的子进程的id),最后再过5秒后程序结束

如上,

第一个红框里就是父进程和子进程一起运行的结果

第二个红框就是子进程运行结束正常退出进程,变为僵尸进程,然后父进程继续运行

第三个红框就是父进程等待子进程成功,子进程正常退出

如果想看子进程异常退出就可以把waitpid的第一个参数改为不是这个父进程的子进程的pid即可

如果想看到子进程异常退出,则可以用信号杀死子进程

非阻塞轮询:

这里就需要使用waitpid的第三个参数:options

非阻塞轮询的核心在于“非阻塞”,即程序在等待某个事件时,不会使进程进入等待状态,而是立即返回一个状态码(waitpid返回0),程序可以继续执行其他任务,当再次调用waitpid的时候,程序再次检查

在waitpid中第三个参数,如果设置为0的话就和wait一样了,父进程一直等待子进程直到其退出变为僵尸进程然后被父进程回收,如果设置为WNOHANG的话,若pid(第一个参数)指定的子进程没有结束,则waitpid()函数返回0,父进程不等待子进程;若正常结束,返回子进程的pid

例如,修改代码,将父进程每隔一段时间调用一次waitpid()函数,若此时等待子进程还没有退出,那么父进程就不用还在这等待子进程,而是可以去做其他事,过段时间再调用waitpid()在判断子进程有没有退出,如果此时退出就可以回收子进程的资源

如上:

这就是父进程一开始就直接等待子进程直到子进程退出


http://www.kler.cn/a/415810.html

相关文章:

  • 【计算机网络】核心部分复习
  • 【头歌实训:递归实现斐波那契数列】
  • Vue使用Mockjs插件实现模拟数据
  • 快速排序hoare版本和挖坑法(代码注释版)
  • 对智能电视直播App的恶意监控
  • STM32-- 看门狗--介绍、使用场景、失效场景
  • 用Go语言重写Linux系统命令 -- ping
  • Python读取摄像头视频并将其保存为MP4文件
  • 利用Java爬虫获得店铺详情:技术解析
  • KUKA机器人中断编程5—自动回原点功能的编程
  • 工程企业如何做好成本控制?该如何入手?
  • 和鲸科技创始人CEO范向伟出席首届工业智算产业发展研讨会,共话 AI 创新与产业化落地
  • 在windows系统中安装python并确认安装成功
  • 中信建投张青:以金融智慧点亮公益新篇章
  • Flink的双流join理解
  • 一次完整的CNAS软件测试实验室内部审核流程
  • Ubuntu-20.04安装 terminator
  • Spring Boot教程之十二: Spring – RestTemplate
  • [巅峰极客 2021]签到
  • 如何具体实现商品详情的提取?
  • 等保测评在云计算方面的应用讲解
  • 从覆盖到拼接:优化 onInput 事件的输入
  • uniapp开发微信小程序笔记8-uniapp使用vant框架
  • 3.26线性回归对率回归
  • 家校通小程序实战教程02口令管理
  • 【SCT61240QFJCR】用于超小型汽车摄像头模块的四通道电源管理IC,国产 车规