初识Linux · 进程终止

目录

前言:

进程终止在干什么

进程终止的3种情况

进程如何终止


前言:

由上文的地址空间的学习,我们已经知道了进程不是单纯的等于PCB + 自己的代码和数据,进程实际上是等于PCB + mm_struct(地址空间) + 页表 + 自己的代码和数据。在地址空间那里我们结合写时拷贝重新理解了进程具有独立性,也理解了为什么fork函数会返回所谓的两个值,那么今天的话题是进程控制,我们拿fork举例,为什么fork返回给父进程的是子进程的pid,而子进程返回的值的0呢? 

这是因为子进程退出的时候,可以将自己的代码和数据退出了,但是自己的PCB还需要维护一段时间,因为父进程需要知道对应的退出信息,退出信息都是维护在PCB里面的,就像是A交给B办一件事,B干的怎么样,A总得知道吧?这个“干的怎么样”,就是B的退出信息。

那么对于进程终止这块内容,本文的介绍方式是:先想清楚进程终止是在干什么,然后理解进程终止的3种情况,最后理解进程如何终止。


进程终止在干什么

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/types.h>int main()
{pid_t id = fork();if(id == 0){printf("I am a child process,I will die\n");}else{sleep(10);printf("I am a father process,I wait\n");}return 0;
}

我们使用如上的代码,观察了一下僵尸进程的现象,子进程结束之后,父进程休眠10秒,这个过程,子进程已经结束了,但是父进程没有回收它,所以子进程短暂的变成了僵尸进程。

这里提问,进程创建的时候,是自己的代码和数据先过去还是PCB那些数据结构先过去呢?

结合上大学的时候,是你的数据先过去还是人先过去来思考哦~ 

那么当你毕业了,你的数据是否瞬间就没有了呢?你的人当然是先走了,但是数据总得维护一段时间吧?进程这里同理,当进程终止的时候,进程的代码和数据所占据的空间是被释放了,但是,进程的PCB是需要被维护一段时间的,因为要记录退出信息,此时有一个对应的状态就是zombie,即僵尸进程。

所以进程终止的时候,第一个要干的事就是对应的代码和数据占据的空间先释放掉,然后是进程对应的PCB被维护起来,整个进程的状态变成僵尸,等待回收,对应的退出信息记录在PCB里面,此时进程终止的操作也就完成了,剩下的是等待父进程来回收即可。


进程终止的3种情况

进程终止的3种情况,分别是代码正常,结果正确,代码不正常,结果不正确,以及代码执行的时候,出现了异常,提前退出了,这是3种情况,介绍的时候即围绕这三种情况进行讲解。

思考一个问题:为什么C语言阶段我们写main函数默认要返回的是0呢?为什么不是1?不是100呢?

int main()
{return 1;
}
int main()
{return 0;
}
int main()
{return 100;
}

这三种代码我们放在VS跑都是没有问题的,那么是不是代表main函数的返回值我们可以随便返回呢?

当然不是,在C语言阶段我们只是在语言层面知道了可以返回值而已,但是返回给的谁的我们是不知道的。在Linux阶段,我们通过了解退出码这个知识点,就会知道main的返回值怎么回事。

相信大部分人都知道error,错误码,当我们程序报错的时候,会返回错误码,我们可以打印出来看看:

#include<string.h>int main()
{for(int errcode = 0; errcode <= 255; errcode++){printf("%d: %s\n", errcode, strerror(errcode));}return 0;
}

从133开始,就没有错误码了,所以是unknown,那么第一个错误码,也就是0,表示的意思是success,也就是成功,程序成功运行的时候并且结果正确,返回的错误码是0,也就代表了成功。

现在是知道了错误码,那么我们可以通过命令echo $? 来看到对应的错误码:

看这个2,是不是很熟悉?就是我们刚才的No such file or directory,对于错误码,系统有自己的一套规范,但是错误码是可以自己自定义的,也就是说,我们可以拥有自己的一套错误码的体系:

比如:

int main()
{for(int errcode = 0; errcode <= 255; errcode++){printf("%d: %s\n", errcode, strerror(errcode));}return 100;
}

我们自己规定返回的是100,那么退出码就是100,因为echo是内建命令,直接获取到的父进程的资源,那么bash创建的子进程main,再获取到了退出码为100,这就是退出码

退出码唯一的一个稍微规范的是0为success,!0为失败,但是失败的具体原因是我们自己规定的,而不是错误码那样,系统已经规定好了。

但是echo $?只能获取最近的一个进程的退出码:

得到结论:退出码可以默认,也可以自定义

进程如果正常运行,结果是否正确,都只需要一个退出码即可,父进程就可以知道这个进程的情况是什么样的。

进程如果是异常终止的呢?

比如我们写了一个死循环,进程自己停下来不了,我们使用kill发送9号信息码,进程被杀死,就会:

此时,我们看到对应的错误码是137,可是错误码还有意义吗?实际上没有,因为进程异常终止的本质,就是OS给了进程信号,比如:

int main()
{int* p = NULL;*p = 0;return 0;
}

这段代码是一定会报错的:

此时报错,

专业点讲叫做段错误

本质上就是发生了异常,此时进程收到了OS给的信号,并终止:

kill11号命令,SIGSEGV,就是上面的缩写:

int main()
{while(1){printf("Hello Linux,pid is %d\n",getpid());sleep(1);}return 0;
}

此时我们使用11号信号终止进程,就会报段错误,实际上就是进程收到了OS的信号。

也就是说,如果进程异常终止了,退出码是没有用的,退出码只有在程序正常运行的时候有用,进程如果是异常终止,我们想要知道进程为什么异常,就应该查看信号码了,怎么查看,我们在进程等待章节提及。

源码中,进程退出的时候,对于exit_code exit_signal就需要维护,即对应上面的三种情况。 


进程如何终止

进程如何终止的呢?难道是程序运行结束就终止了吗?

不完全是,如果程序是:


int main()
{return 0;
}

如果是main函数运行到了return 0 ,此时进程代表终止,但是如果是其他函数碰到了return 0,只能说是函数结束,这是第一种情况。

进程终止的第二种情况是exit,我们可以使用两个函数,exit _exit:

int main()
{printf("hello 111\n"); sleep(2);//_exit(3);
}

这段代码和缓冲区有关,大家应该知道怎么回事,今天我们这样写:

int main()
{printf("hello 111"); sleep(2);exit(3);
}

可以看到对应的退出码是3,和return效果好像是一样的,因为进程终止,所以会强制刷新缓冲区,即不是先打印,是先休眠的。

此时我们使用系统接口_exit,刚才的exit我们在C语言阶段就使用过,这是库函数,使用_exit呢?

欸?运行了之后为什么什么也没有?

可是对应的退出码也有。

这里,第一个点是exit _exit运行到了都会直接进程终止,并且退出码是exit _exit里面的num,第二点,缓冲区的刷新,_exit调用了没有打印,代表缓冲区没有刷新,我们之前有一个图:

C库函数在系统调用的上方,系统调用在OS的上面,也就是说,exit刷新的缓冲区一定不在OS里面,因为它没有权限,_exit才有资格接触OS,这就说明刷新的缓冲区是在C库函数的上面,得出结论,目前我们说的缓冲区,并不是内核缓冲区!

这是两种进程终止所引发的缓冲区的一个知识点,进程终止我们可以使用return 也可以使用exit,也可以使用_exit,区别就是缓冲区的刷新,但是对于PCB里面的exit_code exit_signal都是要维护的,无非就是缓冲区的刷新而已。

进程终止的更多小点会放在进程等待,即下篇文章哦~


感谢阅读!

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

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

相关文章

PCL 法线空间采样

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 法线计算 2.1.2 基于法线进行采样 2.1.3 可视化原始点云和采样后的点云 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实…

戴尔电脑怎么开启vt虚拟化_戴尔电脑新旧机型开启vt虚拟化教程

最近使用戴尔电脑的小伙伴们问我&#xff0c;戴尔电脑怎么开启vt虚拟。大多数可以在Bios中开启vt虚拟化技术&#xff0c;当CPU支持VT-x虚拟化技术&#xff0c;有些电脑会自动开启VT-x虚拟化技术功能。而大部分的电脑则需要在Bios Setup界面中&#xff0c;手动进行设置&#xff…

CEPH的写入流程

1、客户端程序发起对文件的读写请求&#xff0c;ceph前端接口&#xff08;RADOS Gateway&#xff09;将文件切分成多个固定大小的对象&#xff08;默认大小为4MB&#xff09; 2、计算文件到对象的映射 (1) 计算OID为每个对象分配一个唯一的OID&#xff08;Object ID&#xff09…

跟着谭书学c语言---110页第5章循环结构(5.1和5.2节)

目录 5.1节读书笔记 5.2节读书笔记 总结和反思 5.1节读书笔记 5.2节读书笔记 几点说明:::用小规模数据测试程序的正确性,加断点,打印中间状态 关于程序分析(2)深刻体会循环前的初始化,同样的功能如果初始化条件不同,循环有可能会有细微的变化 循环体中,语句进行调…

[Linux]僵尸进程,孤儿进程,环境变量

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;大大会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

C++ string的基本运用详细解剖

string的基本操作 一.与C语言中字符串的区别二.标准库中的string三.string中常用接口的介绍1.string中常用的构造函数2.string类对象的容量操作函数3.string类对象的访问及遍历操作4.string类对象的修改操作5.string类的非成员函数6.string中的其他一些操作 一.与C语言中字符串…

软考论文《论大数据处理架构及其应用》精选试读

论文真题 模型驱动架构设计是一种用于应用系统开发的软件设计方法&#xff0c;以模型构造、模型转换和精化为核心&#xff0c;提供了一套软件设计的指导规范。在模型驱动架构环境下&#xff0c;通过创建出机器可读和高度抽象的模型实现对不同问题域的描述&#xff0c;这些模型…

《Windows PE》3.2 PE头结构-DOS头和DOS块

正如我们在初识PE文件一节中看到的&#xff0c;PE文件头中包含几个重要的结构&#xff0c;DOS头、DOS块&#xff08;DOS Stub&#xff09;和NT头。NT头就是PE特征码文件头&#xff08;COFF 文件标头&#xff09;扩展头&#xff08;可选标头&#xff09;&#xff0c;合称为NT头。…

Anki 学习日记 - 卡片模版 - 单选ABCD(纯操作)

摘要&#xff1a;在不懂前端语言的情况下自定义卡片模版&#xff0c;卡片模版的字段 安装&#xff08;官网&#xff09;&#xff1a;Anki - powerful, intelligent flashcards (ankiweb.net) 一、在哪能修改卡片模版 管理笔记模板 - > 添加 -> 问答题 -> 设置名称 二…

建筑物变化检测算法baseline工程,开箱即用,23年5月测试准确度超越阿里云aiearth

建筑物变化检测算法baseline工程&#xff0c;开箱即用&#xff0c;23年5月测试准确度超越阿里云aiearth 建筑物变化检测算法Baseline工程 项目背景 随着城市化进程的加快&#xff0c;对建筑物的变化进行监测变得尤为重要。这不仅有助于城市管理与规划&#xff0c;还能够为灾害…

Flutter路由

路由作为一种页面切换的能力&#xff0c;非常重要。Flutter 中路由管理有几个重要的点。 Navigator 1.0&#xff1a;Flutter 早期路由系统&#xff0c;侧重于移动端 &#xff0c;命令式编程风格&#xff0c;使用 Navigator.push() 和 Navigator.pop() 等方法来管理路由栈。 N…

多处理器的概念与对比

SISD, SIMD, MISD, 和 MIMD 代表了并行计算的四种基本架构&#xff0c;它们描述了处理器如何处理指令和数据。 理解这些架构的关键在于区分指令流&#xff08;Instruction Stream&#xff09;和数据流&#xff08;Data Stream&#xff09;是单一的还是多重的。 1. SISD (Singl…

04 B-树

目录 常见的搜索结构B-树概念B-树的插入分析B-树的插入实现B树和B*树B-树的应用 1. 常见的搜索结构 种类数据格式时间复杂度顺序查找无要求O(N)二分查找有序O( l o g 2 N log_2N log2​N)二分搜索树无要求O(N)二叉平衡树无要求O( l o g 2 N log_2N log2​N)哈希无要求O(1) 以…

彩虹易支付最新版源码及安装教程(修复BUG+新增加订单投诉功能)

该系统也没版本号&#xff0c;此版本目前是比较新的版本&#xff0c;增加了订单投诉功能&#xff0c;和一个好看的二次元模板。 此版本是全开源版&#xff0c;无一处加密文件,系统默认是安装后是打不开的&#xff0c; 本站特别修复了BUG文件&#xff0c;在PHP7.4环境下也没问…

ISA-95制造业中企业和控制系统的集成的国际标准-(2)

ISA-95 文章目录 ISA-95ISA-95企业层和制造运营管理层信息模型一、企业层和制造运营管理层信息模型内容二、企业层和制造运营管理层信息模型分类 ISA-95企业层和制造运营管理层信息模型 ISA-95信息模型是指ISA-95制造业中企业和控制系统集成的国际标准定义了企业层和制造运营层…

二值图像的面积求取的两种MATLAB方法

一、引言 面积在数字图像处理中经常用到&#xff0c;在MATLAB中&#xff0c;计算二值图像的面积通常可以通过两种主要方法实现&#xff1a;遍历法和直接利用bwarea函数。下面将分别介绍这两种方法的原理和相应的MATLAB代码示例。 二、遍历法计算二值图像面积的原理和MATLAB代码…

Stable Diffusion绘画 | 来训练属于自己的模型:素材处理与打标篇

纵观整个模型训练流程&#xff0c;图片素材准备和打标环节占据的分量比重&#xff0c;绝对超过60%。 上一篇分享了图片素材准备&#xff0c;这一篇&#xff0c;开始对准备好的图片素材进行处理了。 素材处理 我已经收集了 霉霉 的25张图片&#xff1a; 但是&#xff0c;发现…

Goland 设置GOROOT报错 The selected directory is not a valid home for Go SDK

问题描述 将go版本从1.16升级到1.22时配置GoRoot报错了如下图问题 The selected directory is not a valid home for Go SDK起因的是我的这个goland比较老了&#xff0c;2020年的。所以需要设置下版本 解决 OK&#xff0c;说一下解决办法&#xff1a; 找到go的安装路径&am…

Linux之进程概念

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux专栏 创作时间 &#xff1a;2024年9月28日 基本概念&#xff1a; 进程说白了其实就是一个程序的执行实例&#xff0c;正在执行的程序。 在内核层面来说&#xff0c;就是一个担当分配资源&#xff08;CPU时间…

基于大数据可视化的图书推荐及数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…