【Linux】详解进程终止进程等待

一、页表&&写时拷贝的进一步理解

        页表中不仅仅只有虚拟地址到物理地址的映射,还包括了很多选项,其中就包括了映射条目的权限。当我们进程的代码和数据加载到内存并和进程地址空间建立映射关系时,如果数据的内容不允许被修改(比如说常量字符串),对应数据在页表中的映射条目的权限就会被设置为'r',表示该数据是只读的,不能被修改。这就是为什么当我们要对常量字符串的内容做修改程序运行阶段会报错的底层原因。

        通过页表的权限位,我们也可以很好地解释写时拷贝是如何做到的。当父进程创建子进程时会发生写时拷贝,写时拷贝会把大部分映射条目的权限都由‘rw’设置成‘r’。当子进程或者是父进程要对数据进行修改时,发现要修改数据对应的映射条目的权限位‘r’,无法进行修改,这时操作系统就会介入。操作系统发现子进程(假设是子进程要对数据进行修改)要对数据进行修改,且操作时合法的,这是就会在内存中申请一块空间重新建立映射关系,再将父子进程该对应的映射条目都改成‘rw’,这才算完成了一次写时拷贝。通过以上过程操作系统就可以按需进行写时拷贝。

二、进程终止

        main函数的返回值我们叫做进程的退出码。一般0表示进程执行成功,非0表示进程执行失败可以用非0的数字表示进程失败的原因。错误码可以转换成错误描述,可以使用语言和系统自带的方法进行转化,也可以自定义。其他函数错误码仅仅表示函数调用结束。

2.1、echo $?

        bash进程会记录最近一个进程退出的退出码,可以查看echo $?可以查看最近一个进程退出的退出码。

        调用函数我们通常想看到两种结果,一是函数的执行结果(比如说fopen打开文件,打开成功就返回文件指针,打开失败返回NULL,这叫函数的执行结果),二是函数的执行情况(比如说同样是fopen打开文件,我们函数的执行情况对应的数字会被保存在errno(错误码)这个变量中)。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main()
{FILE* fp = fopen("./log.txt", "r");printf("%d %s\n", errno, strerror(errno));return 0;
}

 错误码和main函数的退出码本质上是一样的。 错误码只会记录系统提供的函数的执行情况

2.2、进程退出的场景

进程提出的场景与三种:

1、进程代码执行完了,结果是正确的。

2、进程代码执行完了,结果不正确。

3、进程代码没有执行完,进程出异常了。进程出异常时,进程的退出码是没有意义的。

         第三种情况进程出异常是进程收到了操作系统发出的异常信号,每个信号都有不同的编号,不同的信号编号表示异常的原因。

        任何进程最终的执行情况我们都可以用两个数字来表示。一个是进程的退出信号(exit_signal)(退出信号为0表示进程没有出异常),一个是进程的退出码(exit_code)进程的退出信号是由操作系统发送给进程,以指示进程应该终止或进行某种操作的信号,是上对下的操作。而进程的退出码则是当进程结束运行时返回给操作系统的一个整数值,用于表示进程的执行状态或结果,是下对上返回的结果。

2.3、exit

        exit就是用来终止进程的,exit括号中的内容就是进程的退出码。在我们的代码进程中,在任意地方调用exit都表示进程退出

三、进程等待

3.1、进程等待的必要性

1、之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。

2、另外,进程一旦变成僵尸状态,那就刀枪不入,kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。

3、最后,父进程派给子进程的任务完成的如何,我们需要知道。如子进程运行完成,结果对还是不对,或者是否正常退出。

4、父进程通过进程等待(wait)的方式,回收子进程资源,获取子进程退出信息

 3.2、进程等待的方法

3.2.1、wait方法

        wait方法里的参数为输出型参数,可以设置为NULL。调用wait函数父进程默认进行阻塞等待,会等待任意一个子进程退出。等待成功,wait会返回子进程的pid,等待失败返回小于0的值。 

        fork之后父子进程谁先运行不确定,但fork之后一定是父进程后退出,因为父进程要回收子进程。

3.2.2、waitpid方法

        以上pid参数为要回收子进程的pid(pid如果为-1,表示等待任意一个子进程,与wait等效),wstatus参数同样为输出型参数,可以设置为NULL(也可以设置为一个int变量的地址,可以查看子进程的退出码), options参数设置为0表示阻塞等待,设置为宏 WNOHANG表示非阻塞等待采用非阻塞的方法等待,子进程退出成功返回子进程的pid,子进程还在继续自己的工作返回0,子进程出错返回小于0的数。阻塞等待时父进程会阻塞在waitpid这里一直等待子进程返回,非阻塞等待采用轮询的方法查看子进程的退出信息,在轮询的间隙父进程可以继续做别的工作。

3.2.3、wstatus参数详解

        *wstatus表示一个int整形变量,由三十二个比特位组成,其中前16个比特位我们不用,第17到第24个比特位用来表示进程退出时的退出码,第26到第32个比特位用来表示进程退出时收到的退出信号。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t id = fork();if(id == 0){// childint cnt = 5;while(cnt){printf("Child is running, pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);cnt--;}exit(1);}int status = 0;pid_t rid = waitpid(id, &status, 0); // 阻塞等待if(rid > 0){printf("wait success, rid: %d, status: %d\n", rid, status);}return 0;
}

 

        这就可以解释为什么上面的status变量为256了。因为子进程的退出码为1,status的第24个比特位被设置为1,没有收到退出信号,所以status后8个比特位都为0,所以status等于2的8次方等于256。 

3.2.4、使用位操作从status变量中提取出进程的退出信号和退出码。

int main()
{pid_t id = fork();if(id == 0){int cnt = 5;while(cnt){printf("Child is running, pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);cnt--;}exit(1);}int status = 0;pid_t rid = waitpid(id, &status, 0); // 阻塞等待if(rid > 0){printf("wait success, rid: %d, status: %d, exit_signal: %d, exit_code: %d\n", rid, status, status&0x7f, (status>>8)&0xff);}return 0;
}

 3.2.5、使用宏获取进程的退出码

        一般用户不是很关心进程的退出状态只想获取子进程的退出码就可以使用这种方法。

WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)。

WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)。

int main()
{pid_t id = fork();if(id == 0){int cnt = 5;while(cnt){printf("Child is running, pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);cnt--;}exit(1);}int status = 0;pid_t rid = waitpid(id, &status, 0); // 阻塞等待if(WIFEXITED(status)){printf("wait success, rid: %d, status: %d, exit_code: %d\n", rid, status,WEXITSTATUS(status));}return 0;
}

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

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

相关文章

linux查找指定目录下包含指定字符串文件,包含子目录

linux查找指定目录下包含指定字符串的文件&#xff0c;包含子目录 linux查找指定目录下包含指定字符串的指定文件格式&#xff0c;包含子目录 指定目录 cd /home/www/linux查找指定目录下包含指定字符串的文件&#xff0c;包含子目录 grep -r "指定字符串"注释 gr…

在 Linux CentOS 中安装 Docker Engine(Dockers 引擎)【图文详解】

官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 操作系统要求 如果我们要在 CentOS 中安装 Docker 引擎&#xff0c;那么 CentOS 操作系统需要是以下版本之一的&#xff0c;且是处于维护的 CentOS 版本&#xff1a; CentOS 7CentOS Stream 8CentOS Str…

基于Springboot的牙科就诊管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的牙科就诊管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍: 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c…

stable diffusion 的 GPU 不足怎么解决

稳定扩散&#xff08;stable diffusion&#xff09;是一种用于图像处理和计算机视觉任务的图像滤波算法。 当使用Stable Diffusion过程中遇到GPU显示内存不足的问题时。解决这个问题的方法有以下几种&#xff1a; 目前&#xff0c;对我来说&#xff0c;就最后一点能够暂时解决当…

显示器接口的了解

显示器视频接口科普&#xff1a;看完就懂HDMI、DP、DVI、VGA、USB-C哪个更适合你的电脑外接显示器_哔哩哔哩_bilibili 电脑显示接口&#xff1a; VGA,DVI,HDMI,DP,USB-C VGA:基本被淘汰了。 常见的还是HDMI1.4和2.0规格 更适合电脑使用的DP接口&#xff08;免费&#xff09;…

笔记本作为其他主机显示屏(HDMI采集器)

前言&#xff1a; 我打算打笔记本作为显示屏来用&#xff0c;连上工控机&#xff0c;这不是贼方便吗 操作&#xff1a; 一、必需品 HDMI采集器一个 可以去绿联买一个&#xff0c;便宜的就行&#xff0c;我的大概就长这样 win10下载 PotPlayer 软件 下载链接&#xff1a;h…

以太网交换——数据链路层

目录 一.以太网工作机制 网卡 交换机工作机制 二.虚拟局域网——vlan划分 1.虚拟局域网 2.怎么区分各个部门&#xff0c;打标签 一.以太网工作机制 早期以太网是同轴电缆连接的&#xff0c;只是传输介质&#xff0c;并不对数据做任何处理。 为解决信号冲突&#xff0c;…

2024年最新阿里云服务器价格表_CPU内存+磁盘+带宽价格

2024年阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核4G服务…

Redis入门到实战-第十六弹

Redis实战热身Cuckoo filter篇 完整命令参考官网 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是一个开源的&#xff08;采用BSD许可证&#xff09;&#xff0c;用作数据库、缓存、消息…

深入理解C语言宏定义

目录 一、前言 二、宏的相关语法 2.1 #define 2.2 #undef 2.3 #运算符 2.4 ##运算符 三、宏替换的规则 四、宏与函数 一、前言 我们都知道#define语句可以定义常量&#xff0c;在编译器预处理时会全部将名字替换为常量。与此同时&#xff0c;#define也允许把参数替换到…

发展的挺快的Rust

C 可能在将来会逐步的退出历史舞台 Rust 在linux 上出现的频次越来越多了 新的语言和重构带来了更方便快捷的体验 好玩的命令集合 https://github.com/ibraheemdev/modern-unix.git 这速度&#xff0c;这花活儿

SpringBoot整合Swagger-UI实现在线API文档

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot整合Swagger-UI实现在线API文档 📚个人知识库: Leo知识库,欢迎大…

【深度学习基础(4)】pytorch 里的log_softmax, nll_loss, cross_entropy的关系

一、常用的函数有&#xff1a; log_softmax,nll_loss, cross_entropy 1.log_softmax log_softmax就是log和softmax合并在一起执行&#xff0c;log_softmaxlogsoftmax 2. nll_loss nll_loss函数全称是negative log likelihood loss, 函数表达式为&#xff1a;f(x,class)−x[…

市场复盘总结 20240327

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 14% 最常用…

Unity连接MySQL踩坑,问题处理记录

用的unity2021版本&#xff0c;MySQL是官方下载的最新版8.0.36. 安装MySQL时&#xff0c;过去如果安装过&#xff0c;一定要删干净&#xff0c;单纯的卸载不行&#xff0c;网上有很多教程。 MySQL安装完成后&#xff0c;将安装目录的MySql.Data.dll文件放入unity项目的Plugin…

Oracle数据库管理:从基础到高级应用【文末送书-45】

文章目录 入门篇&#xff1a;初识Oracle进阶篇&#xff1a;深入学习Oracle精通篇&#xff1a;掌握Oracle高级技术Oracle从入门到精通&#xff08;第5版&#xff09;&#xff08;软件开发视频大讲堂&#xff09;【文末送书-45】 在当今数字化时代&#xff0c;数据是企业成功的关…

Git基础(23):Git分支合并实战保姆式流程

文章目录 前言准备正常分支合并1. 创建两个不冲突分支2. 将dev合并到test 冲突分支合并1. 制造分支冲突2. 冲突合并 前言 Git分支合并操作 准备 这里先在Gitee创建了一个空仓库&#xff0c;方便远程查看内容。 正常分支合并 1. 创建两个不冲突分支 &#xff08;1&#xf…

学校管理系统项目——数据架构设计方案

学校作为一个组织机构&#xff0c;需要管理大量的信息和数据&#xff0c;包括学生信息、教师信息、课程信息、成绩信息等。为了更高效地管理这些数据&#xff0c;提升学校管理水平和服务质量&#xff0c;本文对学校数据管理系统的需求进行了分析与总结&#xff0c;旨在为学校选…

鸿蒙OS应用示例:【数字滚动计时】

实现效果&#xff1a; 代码示例&#xff1a; RollingText.ets 组件封装 RollingText.ets 组件封装 /*** 滚动文字特效*/ Component export default struct RollingText {private num:numberprivate timerId: number -1State counter: number 0aboutToAppear() {this.timerId…

2024年上半年数学建模竞赛一览表(附赠12场竞赛的优秀论文+格式要求)[电工、妈杯、数维、五一等12场]

为了帮助大家更好地备战今年上半年十二场数学建模竞赛&#xff0c;我们为大家收集到了这十二场相关竞赛的优秀论文以及格式要求&#xff0c;具体内容如下所示。 资料获取 在文末 文中资料来源 名称竞赛官方网站天府杯https://www.tfmssy.org.cn/认证杯http://www.tzmcm.cn/i…