[linux]进程控制——进程等待

一、概念

进程等待,就是通过wait/waitpid的方式,让父进程(一般)对子进程进行资源回收的等待过程。

二、原因

(1)

当一个进程在退出的时候,如果不回收,就会变成僵尸状态,它让父进程等待之后,将僵尸状态进行回收。

僵尸就是进程或者子进程对应的代码和数据已经被释放,但是它的PCB以及它进程退出的相关数据依旧被维护,需要让父进程得知它的退出结果。

总结:

解决子进程僵尸问题带来的内存泄漏问题(是必须的)

(2)

父进程创建子进程,是为了让子进程帮助父进程完成父进程分配给子进程的任务。

所以,父进程需要知道子进程任务的完成情况。

总结:

需要通过进程等待的方式,获取子进程退出的信息。(不是必须的,但是系统需要提供这样的基础功能(可以不用,但不能没有))

三、如何实现进程等待

1、wait

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

返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

演示:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void Worker()
{int cnt = 5;while(cnt){printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);cnt--;sleep(1);}
}int main()
{pid_t id = fork();if(id == 0){//子进程Worker();exit(0);}else {sleep(10);pid_t rid = wait(NULL);if(rid == id){printf("wait sucess, pid:%d\n",getpid());}}return 0;
}
运行结果:

监视:

可以看出子进程运行完毕之后,在父进程sleep的时间内,子进程是Z状态(僵尸状态)

随后父进程wait,子进程被回收,不再是僵尸状态。

 

思考:

如果将代码中的sleep(10)删除,即表示父进程一开始直接执行到wait,那么情况又是什么样的呢?

运行结果:

 

监视:
 
总结:

进程等待能够回收子进程僵尸状态,Z->X

如果子进程没有退出,父进程必须在wait上进行阻塞等待,直到子进程僵尸,wait自动回收,返回。

 

2、waitpid

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID

演示:

(1)效果与wait相同

 waitpid(id,NULL,0)

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void Worker()
{int cnt = 5;while(cnt){printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);cnt--;sleep(1);}
}int main()
{pid_t id = fork();if(id == 0){//子进程Worker();exit(0);}else {//  sleep(10);printf("wait before\n"); // pid_t rid = wait(NULL);pid_t rid = waitpid(id,NULL,0);printf("wait after\n");if(rid == id){printf("wait sucess, pid:%d\n",getpid());}}return 0;
}

(2) status

status是一个int的整数,32bit,我们只考虑status的低16位。status的低16位被划分为三部分:

它的低七位是对应的信号,次低八位是退出的退出码。而剩下的1个bit位是core dump标志。

 

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void Worker()
{int cnt = 5;while(cnt){printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);cnt--;sleep(1);}
}int main()
{pid_t id = fork();if(id == 0){//子进程Worker();exit(2);}else {//  sleep(10);printf("wait before\n"); // pid_t rid = wait(NULL);int status = 0;pid_t rid = waitpid(id,&status,0);printf("wait after\n");if(rid == id){printf("wait sucess, pid:%d, status:%d\n",getpid(), status);}}return 0;
}

 

思考:

我们设置的退出码是2,那么为什么status显示的是512呢?

 退出码是2,根据上面status比特位的分区,我们可以写出status低16位:

那么该二进制转换成十进制,就是512。

 所以,我们不能对status进行整体使用。

使用:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void Worker()
{int cnt = 5;while(cnt){printf("这是子进程,pid:%d, ppid:%d, cnt: %d\n",getpid(), getppid(), cnt);cnt--;sleep(1);}
}int main()
{pid_t id = fork();if(id == 0){//子进程Worker();exit(2);}else {//  sleep(10);printf("wait before\n"); // pid_t rid = wait(NULL);int status = 0;pid_t rid = waitpid(id,&status,0);printf("wait after\n");if(rid == id){printf("wait sucess, pid:%d, rpid:%d, exit sig:%d, exit code:%d\n",getpid(), rid, status&0x7F, (status>>8)&0xFF);}}return 0;
}

 

如此,我们就可以正确显示该进程的退出信号和退出码了。

总结:
  1. 当一个进程异常(收到信号),exit code是没有意义的。
  2. 判定有没有收到信号,exit sig:0(sucess)
  • exit sig:0,exit code: 0 :代码跑完,结果正确。
  • exit sig:0,exit code: 非0 :代码跑完,结果不正确。
  • exit sig:非0   :中间出异常,exit sig的数字表明出现了哪种异常。

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

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

相关文章

SpringBoot的配置文件application.yml的一些常用语法

目录 一、自定义配置数据 &#xff08;1&#xff09;配置简单数据 &#xff08;2&#xff09;配置对象数据 &#xff08;3&#xff09;配置集合数据 二、Value读取配置文件 三、ConfigurationProperties读取配置文件 配置文件的后缀可以是yaml或者yml&#xff0c;写法类似…

超分中使用的损失函数和经典文章

损失函数 https://towardsdatascience.com/super-resolution-a-basic-study-e01af1449e13 在GAN出现之前&#xff0c;使用的更多是MSE&#xff0c;PSNR,SSIM来衡量图像相似度&#xff0c;同时也使用他们作为损失函数。 MSE 表面上MSE直接决定了PSNR&#xff0c;MSE&#xff…

Golang数据类型

文章目录 数据类型的基本介绍基本数据类型整数类型字符类型浮点数类型复数类型布尔类型string类型 常量类型转换基本数据类型相互转换基本数据类型与string的转换 指针类型值类型和引用类型 数据类型的基本介绍 数据类型的基本介绍 Go中的每一种数据都定义了明确的数据类型&…

从迷宫问题理解dfs

文章目录 迷宫问题打印路径1思路定义一个结构体要保存所走的路径&#xff0c;就需要使用到栈遍历所有的可能性核心代码 部分函数递归图源代码 迷宫问题返回最短路径这里的思想同上面类似。源代码 迷宫问题打印路径1 定义一个二维数组 N*M &#xff0c;如 5 5 数组下所示&…

Linux的UDEV机制

udev 机制引入&#xff1a; 手机接入Linux热拔插相关 a. 把手机接入开发板 b. 安装adb工具&#xff0c;在终端输入adb安装指令&#xff1a; sudo apt-get install adb c. dmeg能查看到手机接入的信息&#xff0c;但是输入adb devices会出现提醒 dinsufficient permissions for …

NTLM认证

文章目录 1.概念(1) 本地认证(2) SAM(3) NTLM Hash(4) NTLM 和 NTLM Hash(5) NTLM v2 1.概念 (1) 本地认证 Windows不存储用户的明文密码&#xff0c;它会将用户的明文密码经过加密后存储在 SAM (Security Account Manager Database&#xff0c;安全账号管理数据库)中。 (2)…

【UnityShader】图片圆角

1.需求 我们在开发的时候&#xff0c;有时候一些按钮或者菜单栏的边角是直角的需要改成圆角&#xff0c;但是让美术重新绘制耽误时间不说也确实没必要&#xff0c;这个时候我们不妨使用一个简单的shader去解决这个问题&#xff0c;下面我们就讲讲这个shader要如何实现。 需求1…

[阅读笔记15][Orca]Progressive Learning from Complex Explanation Traces of GPT-4

接下来是微软的Orca这篇论文&#xff0c;23年6月挂到了arxiv上。 目前利用大模型输出来训练小模型的研究都是在模仿&#xff0c;它们倾向于学习大模型的风格而不是它们的推理过程&#xff0c;这导致这些小模型的质量不高。Orca是一个有13B参数的小模型&#xff0c;它可以学习到…

【BUG】Hexo|GET _MG_0001.JPG 404 (Not Found),hexo博客搭建过程图片路径正确却找不到图片

我的问题 我查了好多资料&#xff0c;结果原因是图片名称开头是_则该文件会被忽略。。。我注意到网上并没有提到这个问题&#xff0c;遂补了一下这篇博客并且汇总了我找到的所有解决办法。 具体检查方式&#xff1a; hexo生成一下静态资源&#xff1a; hexo g会发现这张图片…

本地消息表模式保障分布式系统最终一致性

系统架构说明 状态转换说明 订单表消息表process_queue库存系统return_queue说明成功失败///订单库回滚成功成功失败//订单系统重发消息成功成功成功失败/Broker自动重试&#xff0c;注意接口幂等成功成功成功库存不足退回/Broker通知回掉&#xff0c;订单/消息作废成功成功成…

回溯算法练习day.4

93.复原ip地址 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"…

Kafka导航【Kafka】

Kafka导航【Kafka】 前言版权推荐Kafka随堂笔记 第三章 生产者3.4生产者分区3.4.1.分区好处3.4.2 生产者发送消息的分区策略3.4.3 自定义分区器 3.5 生产经验——生产者如何提高吞吐量3.6 生产经验——数据可靠性3.7 生产经验——数据去重3.7.1 数据传递语义3.7.2 幂等性3.7.3生…