news 2026/4/3 2:10:55

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【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,结果正确。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/1 2:06:19

Dockerfile

目录 前言&#xff1a; 一&#xff0c;Dockerfile 核心理论 1.1、Docker 镜像的分层架构&#xff1a;Dockerfile 的设计基石 1.2、Dockerfile 的构建上下文&#xff1a;指令的作用范围 1.3、Dockerfile 指令的深层执行逻辑 1.3.1. 基础镜像指令&#xff1a;FROM 与 ARG 的…

作者头像 李华
网站建设 2026/3/30 21:27:56

18.0环实现线程和进程的监控(ObRegisterCallbacks函数)-Windows驱动

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;17.过保护读内存&#xff08;通过内核&#xff08;驱动&#xff09;apc的方式附…

作者头像 李华
网站建设 2026/3/28 8:16:51

内容负责人必读:构建企业GEO优化体系的几大关键

在AI驱动的信息检索时代&#xff0c;GEO优化&#xff08;Generative Engine Optimization&#xff09; 已经成为品牌和内容负责人必须掌握的核心策略。与传统搜索引擎优化&#xff08;SEO&#xff09;侧重于提升网站在搜索结果页面中的排名不同&#xff0c;GEO优化专注于让内容…

作者头像 李华
网站建设 2026/4/1 5:02:14

Java毕设项目:基于SpringBoot+Vue技术的医院运营管理系统的设计与实现(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/2 5:49:15

拒绝宕机与丢包:电鱼智能 RK3568 应对工业 EMC 挑战的硬核加固方案

什么是 电鱼智能 RK3568&#xff1f;电鱼智能 RK3568 是一款专为工业控制与网关应用设计的核心计算平台。它搭载 4 核 A55 处理器&#xff0c;支持 ECC 内存纠错&#xff0c;内置 1TOPS NPU。其关键特性在于针对工业场景优化的引脚排布与电气特性&#xff0c;支持宽温工作&…

作者头像 李华