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

【Linux】进程控制(2)进程等待

hello~ 很高兴见到大家! 这次带来的是Linux系统中关于进程控制这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页: 默|笙


文章目录

  • 一、进程等待
    • 1.1 进程等待的必要性
    • 1.2 进程等待的方法
      • 1. wait方法
      • 2. waitpid方法
        • 阻塞等待vs非阻塞等待
      • 3. 获取子进程status

接上次博客---->[进程控制(1)进程创建、终止]。


一、进程等待

1.1 进程等待的必要性

  1. 我们知道一个进程执行完了之后不会立即变成死亡状态,而是变成僵尸状态,如果这个进程的父进程对它不管不顾的话,那么它将一直存在于内存当中,占用系统内存也占用系统所分配的pid。
  2. 处于僵尸状态的进程是无法信号kill -9被杀死的,毕竟谁也无法杀死一个已经死掉的进程。
  3. 其次,父进程派给子进程执行的任务,任务完成的如何我们是需要知道的。比如子进程任务执行结果对不对,是不是正常终止,这部分退出信息是存储在它的task_struct里面。
  4. 既为了不让子进程一直处于僵尸状态(必须),也为了能够知道子进程任务完成的如何,我们需要让父进程对僵尸状态的子进程进行回收—回收子进程资源,获取子进程退出信息。
  • 退出信息储存在子进程的task_struct里面,,,,

1.2 进程等待的方法

1. wait方法

  1. 使用wait需要包含头文件sys/wait.h。
  2. 返回值:如果等待成功返回所等待的子进程的id,等待失败则返回-1。
  3. 关于参数stat_loc,这是一个输出型参数,用来获得子进程的状态,不关心则可以设置成NULL,之后会讲到。
  • 输出型参数:输出型参数的初始值并不重要,因为它是在调用函数后被函数赋值,成为一个函数执行结果的载体,可以通过这个参数获取结果,在这里就是子进程的退出状态。
#include<sys/wait.h>2#include<stdio.h>3#include<unistd.h>4#include<stdlib.h>56intmain()7{8pid_t id=fork();9if(id==0)10{11intcnt=5;12while(cnt--)13{14printf("我是一个子进程!pid:%d, ppid:%d\n",getpid(),getppid());15}16exit(0);//子进程执行完退出17}18sleep(10);19pid_t sid=wait(NULL);20if(sid>0)21{22printf("我是一个父进程!pid:%d,我等待成功了,回收的是pid为%d> 的子进程\n",getpid(),sid);23}24return0;25}


  1. 执行程序之后,子进程执行代码会通过exit终止进程进入僵尸状态,为了不让父进程一下子给子进程回收掉,我让程序sleep了10s,10s过后父进程回收子进程,子进程死亡,父进程执行完代码被bash直接回收,进入死亡状态。
  2. wait方法里:在子进程执行的过程中,父进程会一直处于阻塞状态,父进程会一直等待子进程的结束好对其进行回收,不会做其他的事情。如果想验证可以让子进程休眠5s,让子进程执行的时间久一点,可以观察到父子进程都处于S+状态。
  • wait是回收任意一个已退出处于僵尸状态的子进程,如果没有则为阻塞等待状态。

2. waitpid方法

  1. 同样需要包含头文件sys/wait.h进行使用,不过与wait不同的是,它多了两个参数,一个pid,一个options。

  2. 第一个参数pid是要传给它目标子进程pid,然后它就只会等这个目标子进程,如果想回收任意子进程,就传-1

  3. stat_loc也是输出型参数,用来获取子进程的退出信息。

  4. options默认值为0,表示阻塞等待,即父进程等待子进程的这段时间什么事情都不干,就干等。如果传入WNOHANG(wait no hang不等待),表示非阻塞等待,也就是在等待子进程的时间里面父进程可以干其他的事情

  5. 返回值:在阻塞状态下等待成功则返回所等待子进程的pid,等待失败则返回-1;在非阻塞状态下,如果子进程还没有执行完成则返回0,不继续等待,若正常结束,返回子进程pid。

  • 第一个参数为-1,第三个参数为0时,与wait函数功能相同。
阻塞等待vs非阻塞等待
  1. 打个比方,我烧一壶水,烧这一壶水是需要时间的,阻塞等待就是我一直在这里等着这壶水烧开,这段时间里我什么也不干,就在它旁边守着直到听到它发出咕噜咕噜的声音知道它烧开为止;非阻塞等待就是我在烧这壶水的期间去干其他事情,干一会儿就回来看看水烧开没有,这样既可以等待水的烧开又可以干自己的事情。
  2. 要注意的是,等待的时间是取决于子进程的,无论是阻塞等待还是非阻塞等待要等的时间都是一样的。不存在非阻塞等待比阻塞等待效率高的说法,只能说是非阻塞等待干其他事情的效率提高了
//非阻塞状态实验代码1#include<stdio.h>2#include<unistd.h>3#include<stdlib.h>4#include<sys/wait.h>56intmain()7{8pid_t id=fork();9if(id==0)10{11intcnt=5;12while(cnt--)13{14sleep(1);15printf("我是一个子进程,pid:%d, ppid: %d\n",getpid(),getppid());16}17exit(0);18}19while(1)20{21pid_t sid=waitpid(id,NULL,WNOHANG);22if(sid==0)23{24printf("我是父进程,子进程还没执行完,我要干我自己的事情了\n");25//写父进程等待期间要执行的代码26}27elseif(sid>0)28{29printf("我是父进程,我回收成功了!pid:%d\n",getpid());30exit(0);31}32}33return0;34}
  1. 执行非阻塞等待,第三个参数传入WNOHANG,父进程要使用一个while循环,去不断的使用waitpid()函数进行等待,如果返回值为0则干父进程自己的事情,返回值不为0就回收完毕,父进程终止。差不多就是下面的样子。

3. 获取子进程status

  1. wait函数和waitpid函数都有一个参数status,一个输出型参数,用来获得系统给的子进程的退出信息。
  2. 如果传递的是NULL,则默认不关心子进程的退出状态信息。如果传递的是一个整型变量,那么系统给的子进程的退出信息就会在调用wait/waitpid函数之后存储在这个整型变量里面。

  1. 系统给的退出信息不是一个简单的整数,应该把它当作位图来看待,一个整数4个字节是32bit位,但是退出信息只会存储在16个比特位里面,最高16位一般不会使用。
  2. 在这16个比特位里面,如果是正常终止,那么第8~15个比特位里面会存储子进程的退出状态(0~255),第7位则固定为0,第0~6位为未使用(全为0);如果是被信号所杀,那么第8~15位是没有使用的(全为0),第7位存储的是core dump标志,第0~6位存储的则是终止子进程的信号编号。
  3. 我们可以通过位运算来获取系统给的退出信息,也可以使用系统给的宏来获取:
  1. WIFEXITED(status): 若为正常终止进程返回的状态,则为真(1)。对应(status & 0x7F) == 0,如果信号为0,说明正常终止了。0x7F = 0111 1111。
  2. WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程
    的退出码)对应(status >> 8) & 0xFF,向左移动8位进行提取。0xFF = 1111 1111。
1#include<stdio.h>2#include<unistd.h>3#include<stdlib.h>4#include<sys/wait.h>56intmain()7{8pid_t id=fork();9if(id==0)10{11intcnt=5;12while(cnt--)13{14sleep(1);15printf("我是一个子进程,pid:%d, ppid: %d\n",getpid(),getppid());16}17exit(0);18}19while(1)20{21int*status=NULL;22pid_t sid=waitpid(id,status,WNOHANG);23if(sid==0)24{25// printf("我是父进程,子进程还没执行完,我要干我自己的事情了\n");26//写父进程等待期间要执行的代码27}28elseif(sid>0)29{30printf("我是父进程,我回收成功了!pid:%d\n",getpid());31printf("我是父进程,WIFEXITED:%d, WEXITSTATUS:%d\n",WIFEXITED(status),WEXITSTATUS(status));32exit(0);33}34}35return0;36}

  1. 正常终止,WIFEXITED返回值为1,WEXITSTATUS有意义,返回值为0,代表退出码为0,结果正确。

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!

http://www.jsqmd.com/news/135747/

相关文章:

  • 硬件有限,如何部署“大”模型?AMCT模型压缩工具3步解忧
  • 有关LangChain
  • 软件工程学习日志2025.12.24
  • 52、卷积层(填充paddinng)
  • 用NLMS实现对语音的回声的消除,共4个文件,语音原声,语音回声,NLMS的实现
  • 【毕业设计】基于springboot的公司财务预算管理系统(源码+文档+远程调试,全bao定制等)
  • 乐迪信息:煤矿皮带区域安全管控:人员违规闯入智能识别
  • 49、图像的相关知识
  • 基于VMD分解算法的信号处理与故障诊断:程序化实现及数据预测分类研究
  • 【毕业设计】基于SpringBoot+Vue技术的医疗器械管理系统设计与实现(源码+文档+远程调试,全bao定制等)
  • AUTOSAR学习资料大集合
  • 接口自动化测试框架搭建:从0到1构建企业级解决方案
  • Flutter---轮播图
  • 专利推荐系统实战手记:当协同过滤遇上用户画像
  • 当花朵学会组团解题:新型花授粉算法的暴力美学
  • 50、CNN的概述介绍
  • 2-[(1-戊炔酰基)氨基]-2-脱氧-D-葡萄糖 — 代谢调控研究的新型探针试剂 1635433-54-3
  • 千匠大宗电商系统:赋能煤炭能源行业产业升级
  • 51、卷积层(计算规则)
  • 【协议】vlan
  • 机械臂轨迹规划算法,基于改进灰狼加353多项式的机械臂轨迹规划时间最优算法。 改进灰狼改进的灰...
  • 基于改进鹈鹕算法(IPOA)优化BP神经网络的智能数据回归预测模型——IPOA-BP模型及其评...
  • MATLAB驱动防滑转模型ASR模型 ASR模型驱动防滑转模型 ?牵引力控制系统模型
  • 【技术报告解读】DeepSeek-OCR: Contexts Optical Compression
  • Java毕设选题推荐:基于SpringBoot的非遗产品交流销售平台的设计与实现基于springboot的非遗文化传承与推广平台系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 超越CRUD:在AI时代,用TDD和整洁代码构筑不可替代的护城河
  • 基于LabVIEW的双通道波形发生器:探索信号的多彩世界
  • CI/CD时代的“零容忍“原则:为什么一次破损的主干提交会摧毁整个团队?
  • MATLAB 同步磁阻电机 ESO + PR 控制闭环仿真:转速电流双优的实现
  • 绿电直连项目的审批流程与政策申报指南