linux进程控制——进程创建、运行、exit终止——详解解析!

news2024/11/15 19:52:34

        前言:本篇进入新章节——进程控制。 本章节和上一章节同样都是讲解进程, 但是内容上却比上一章内容好理解的多。上一章内容都是进程的概念性相关, 那个时候我们对于进程的理解还处于小白状态, 所以很多东西很抽象, 不好懂。 但是度过了上一章后, 我们对于linux进程这一方面来说, 就能拥有一些知识储备, 并且用来理解一些计算机现象了。所以, 本篇内容有了上一章的基础会容易理解很多。 

        ps:本篇内容适合已经理解了linux进程概念的友友们进行观看

        

目录

进程创建

创建单个子进程

创建多个子进程

重谈写实拷贝

运行

正常退出

异常终止

exit

exit和_exit区别

缓冲区问题


进程创建

        进程创建的函数就是fork, for在上一章的PCB板块中就讲到过, 并且讲的很深入——我们是从四方面讲解的:在PCB小节分别讲了三个问题——为什么fork给父进程返回子进程pid, 子进程返回0、fork函数究竟干了什么、fork函数如何做到的返回两次;在虚拟地址空间小节又谈了为什么fork明明是一个变量却又两个不同的内容。

        同时也讲解了fork的用法, 但是本节讲重新说一下fork的用法。

创建单个子进程

fork函数的后面都会被创建成为子进程

下面是运行结果:

可以看到, 里面创建了一个进程pid7778,这其实就是子进程。 

创建多个子进程

我们写一段代码如下:

这串一共创建了五个进程, 当每一个子进程跑完之后都会终止结束。 

为了观察, 我们先启动监控脚本:

然后运行程序, 5s内, 运行的结果如下:

当5s结束后,如下图:

由上面的结果我们可以发现, 当我们子进程创建的时候, 父进程和子进程哪一个先运行呢? ——当我们创建多进程的时候, 到底谁先运行, 完全由调度器决定, 也就是谁先被放到队列中, 谁就先被运行。——也就是说, 对于一批子进程来说, 谁先被运行, 并不一定。 

重谈写实拷贝

        写实拷贝博主之前的章节也有说过。 忘记的友友们可以自行复习。 

        写实拷贝其实就是——子进程赋值父进程的PCB以及进程地址空间以及页表。 然后页表的映射物理内存是相同一份数据。 但是当子进程想要修改的时候, 由于进程的独立性, 子进程修改不能影响父进程的数据。 就要发生写实拷贝——重新映射。 

        具体的过程就是下面这样:

        意思就是说, 一开始,子进程拷贝父进程的PCB。 虚拟地址空间, 页表。 所以父子进程中地址空间中的数据段和代码段映射到物理内存也是一样的。 但是这个时候页表会让他们都为只读状态, 如果后续的过程中子进程或者父进程都是只读, 那么就没有问题。 但是只要其中一个发生修改, 那么这个进程对应的页表就会重新映射空间。 这就是写实拷贝的原理。——延时申请、按需申请。

运行

程序运行完毕后有两种状态, 一种是正常退出, 一种是异常终止。 这里将分别讨论一下两种状态:

正常退出

正常退出又分为两个状态, 一个是运行结果正确, 一个是运行结果不正确。 

而运行结果也就是return某个数字或者exit某个数字, 这里的某个数字就是运行结果——也被成为表征码,退出码。用来表示运行结果正确与否:

运行后:

        我们可以使用环境变量? 打印上一次退出码的结果:

        这些运行码的表征结果最终会返回给bash进程。为什么会这样?——这里要思考一个问题:对于进程来说, 谁会关心我运行的情况呢? 一般而言是我们的进程的父进程需要关心。所以会将结果返回给bash进程。 

        哪儿买, 父进程接收退出码, 需要关心什么? 父进程关心子进程, 更多的是关心子进程退出时, 代码跑完后为什么结果是不正确的。 

        而代码的成功只有0, 只要是非0那么就是不正确。 而不正确的非零数字, 就会代表不同的推出原因——退出码。

        对于?来说, 为什么echo $?能狗打印退出码——因为? 是一个环境变量, ? 中保存着上一个执行的进程的退出码, 并且这个只能保留一个。

就比如这个程序, 执行后打印退出码, 可以得到:

再执行一次可以得到:

进程运行后环境变量如下:

但是多运行几次后, 就会出现下图:

        这是因为对于?来说, 第一次打印process的退出码。 但是因为打印要运行echo程序, 这个时候的?里面保存的就是echo的退出码, 正确为0, 所以之后的打印都是0.

        那么, 为什么要有表征码呢? ——对于现阶段来说, 我们打印数据都是打印在硬件显示器上面。 但是未来我们可能并不只是在显示器上面打印, 可能还在网卡网络上面打印。

        但是对于上面的数字来说,我们并不好确认某个数字对应的错误信息。 所以对于用户来说, 我们是不是应该接收到对应的一串字符串信息, 就能更好地接收到进程地错误信息。 ——其实, 系统真的提供了这么遗传信息。 这串信息就是一个接口——strerror, 我们使用man手册可以查看到:

        仙逝后我们就可以看到一个叫做strerror地接口。 这个接口可以将错误码转化为错误的描述信息。 并且打印出来, 我们就可以使用下面的程序进行验证:

        打印的结果就是如下。 可以看到返回0就是成功, 返回1就是操作被限制。 返回2就是没有这个文件。 现在我们来看几条指令, 以及这些指令的结果。

看下面这个指令, 我本想查看一个新文件地信息, 但是这个新文件并不存在, 那么就会打印下面这种情况:

使用echo后, 我们也会发现, 打印的数字和报错信息地对应关系是一样的:

 我们也可以自己实现一个错误码, 这个错误码如下:

想要哪个错误码, 返回相应的下标即可。

        errno可以返回程序最新的错误码, 也就是说, 如果有多次错误, 它就会返回最新一次的, 使用方式如下:

        运行的结果如下:

异常终止

运行异常,对于运行异常来说, 程序的退出码基本可以不看。因为异常就代表没有正常执行到退出程序, 这个时候退出码没有太大意义。 

        现在看一下下图:

         这个程序就是对于零号地址进行解引用, 但是系统层面不允许我们这么做。 这就会给我们发出一个信号, 如下图:

        这上面的就是程序的结果, 对应的意思就是对野指针的解引用。 

        事实上日常中我们也是这样, 如果一个程序发生了异常终止。 ——本质上就是进程收到了对应的信号。

        其实, 如果一般的异常, 一定会触发一些硬件级别的错误。 比如说cpu除零, 那么cpu就会出现一些溢出性错误。 又比如野指针, 野指针就是这个地址在页表中没有建立对应的映射关系。 或者建立了映射关系, 但是权限只是只读, 最终也会转化为硬件问题。 

        这些硬件问题会被操作系统识别, 进而操作系统会向目标进程发信号。

        当我们进程出问题的时候kill -9直接杀掉进程:

        现在来观察一下下面这个进程:

如下图:

现在使用kill -9杀掉进程, 没有问题:

但是, 如果我们给这个程序发一下某个异常信号:

        当我们没有发信号的时候, 这个程序正在正常的跑。——如果不出意外, 这个进程是能够无限循环的, 但是如果我们给进程发一个信号, 那么这个进程就会被检测为异常, 进而被操作系统杀掉。 由此可以看出——进程的本质就是接收到了对应的信号。 

        

exit

exit用来终止进程, exit里面也有退出码:

比如这个进程, 跑不到return就会遇到exit直接终止, 如下图:

现在我们来看这么一串代码, 看看如图是如何进行的:

        请问上面的程序的退出码是什么? ——答案是13, 因为对于exit来说, 无论exit在什么位置, 只要exit出现, 就会终止掉调用该函数的进程。

exit和_exit区别

要解决这个问题, 先看下面的两串代码:

运行结果分别是:

没有什么区别, 但是现在是有\n, 会刷新缓冲区, 我们去掉\n后就会出现问题:

        首先来看一下_exit()

        可以观察到的情况就是:printf打印了一段语句。 但是程序并没有将这段语句打印出来:

按照我们正常的理解, 这个语句是可以打印出来的, 就如同下面的exit:

为什么会这样就是因为_exit是系统调用, exit是上层封装, 就如同下图:

_exit是一个系统调用接口, 正常程序直接调用操作系统接口_exit, 直接在系统层面终止进程。 而exit是先调用这些刷新缓冲区的函数等等, 然后最后再调用_exit来终止进程。

        我们printf显示数据时, 一定是先把数据写入缓冲区, 然后在合适的时候, 再进行刷新!

缓冲区问题

现在我们思考一个问题, 缓冲区, 绝对不在哪里呢?

现在我们来看一下下面的图:

其实这里面上面的就是用户层, 而下面的是内核空间。

那么假如缓冲区在内核空间, 那么_exit也在内核中, 那么当_exit终止进程的时候就能直接刷新缓冲区。 就起到了缓冲的作用, 这和事实矛盾。 所以得到的结论就绝对不在缓冲区。 

以上就是本篇文章全部内容——下面是本节笔记

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速排序的优化--前后指针

前后指针思想 我们前面文章讲的核心思想是haroe的核心思想,将keyi另一边的指针先移动,找比keyi小的,然后不动,再让keyi这边的指针移动,找比keyi大的,但是这种方法的局限性就是需要让keyi另一边的指针先移动…

止损与趋势交易的艺术在昂首平台尽情绽放

在昂首平台上,我们认识到交易不仅仅是数字游戏,更是一门艺术,需要投资者智慧和策略。正如做生意一样。会以125的价格买入商品,然后再以250的价格卖出。没人会不切实际想着以0元的价格购买商品再以高价卖出。 交易同样需要合理的成…

云仓技术带来的物流变革影响

1、实时可视性: 云仓技术使物流公司能够实时跟踪和监控货物在供应链中的位置和状态。这种实时可视性提供了更好的货物追踪和管理能力,同时也提高了客户服务的质量。 ———————————————————— 2、仓储优化: 云仓技术可以…

【管理咨询宝藏145】多元化经营大型集团组织架构优化提升方案

【管理咨询宝藏145】多元化经营大型集团组织架构优化提升方案 【格式】PDF版本 【关键词】组织架构、人力资源、组织管控 【核心观点】 - 随着多元业务的发展, 公司逐步由百亿级企业向干亿级企业转变, 人才布局将面临一系列挑战 - 挑战1 :为支撑公司多业…

前端工程化-vue项目开发流程

vue项目创建参考该文&#xff1a; 前端工程化-vue项目创建-CSDN博客 组件就是页面的意思&#xff1b; 默认的App.vue根组件如下图 我们可以修改为如下图所示&#xff0c;注意script的选择&#xff0c; <html>中的标签&#xff0c;此处是放在<template>中&#…

[php7系列]--php7里的返回类型声明和标量类型声明及不要用isset判断数组是否定义某个KEY-最好使用array_key_exists

一、[php7系列]--php7里的返回类型声明和标量类型声明 php7里增加了返回类型声明和标题类型声明&#xff0c;可以理解为对一个方法的输入输出进行了类型验证&#xff0c;在PHP7之前&#xff0c;方法里的数组、对象参数是有类型声明的&#xff0c;但其它的整数、字符串等类型声明…

Idea设置自动导包

Idea设置自动导包 【File】→【Setting】(或使用快捷键【Crlt Shift S】)打开Setting设置。 点击【Editor】→【General】→【Auto Import】。勾选自定导包的选项&#xff0c;并确定&#xff0c;如下&#xff1a;

心大陆AI科学养育,共情陪伴孩子的幸福童年!

3-8岁是宝宝的关键期&#xff0c;在这个阶段也是父母最费心的时候&#xff1a;孩子吃饭、洗澡、睡觉总爱拖延、玩玩具三分钟热度、上课小动作多、语言能力弱&#xff0c;讲话不连贯容易暴怒、天性好奇&#xff0c;总有十万个为什么等等...... 这些情况在儿童早期发育阶段爸爸妈…

优思学院|如何透过客户忠诚度分析决定六西格玛改善项目?

客户忠诚度分析提供了一个框架&#xff0c;从而便于公司理解客户不再忠诚的原因&#xff0c;并做出相应的改善。客户忠诚度不仅是要关注现有的客户&#xff0c;还应包括已失去的客户。客户忠诚度研究有助于公司发现使客户转向竞争对手的有关客户服务、产品或可靠性等的一些问题…

论文阅读:A Survey on Evaluation of Large Language Models-鲁棒性相关内容

A Survey on Evaluation of Large Language Models 只取了鲁棒性相关的内容 LLMs&#xff1a;《A Survey on Evaluation of Large Language Models大型语言模型评估综述》理解智能本质(具备推理能力)、AI评估的重要性(识别当前算法的局限性设 对抗鲁棒性是衡量大型语言模型&…

C语言进阶 11.结构体

C语言进阶 11.结构体 文章目录 C语言进阶 11.结构体11.1. 枚举11.2. 结构类型11.3. 结构与函数11.4. 结构中的结构11.5. 类型定义11.6. 联合11.7. PAT11-0. 平面向量加法(10)11-1. 通讯录的录入与显示(10) 11.1. 枚举 常量符号化: 用符号而不是具体的数字表示程序中的数字 cons…

基于FPGA的数字信号处理(19)--行波进位加法器

1、10进制加法是如何实现的&#xff1f; 10进制加法是大家在小学就学过的内容&#xff0c;不过在这里我还是帮大家回忆一下。考虑2个2位数的10进制加法&#xff0c;例如&#xff1a;15 28 43&#xff0c;它的运算过程如下&#xff1a; 个位两数相加&#xff0c;结果为5 8 1…

Linux系统配置STM32的开发环境(代码编辑,编译,下载调试)

常见的stm32开发都是直接使用keil-MDK工具的&#xff0c;这是个集成开发环境&#xff0c;包含了代码编辑&#xff0c;编译&#xff0c;下载&#xff0c;调试&#xff0c;等功能&#xff0c;而且keil还是个图形化操作工具&#xff0c;直接可以点击图标案件就可以实现编译下载啥的…

实现物理数据库迁移到云上

实现物理数据库迁移到云上 以下是一个PHP脚本,用于实现物理数据库迁移到云上的步骤: <?php// 评估和规划 $databaseSize = "100GB"; $performanceRequirements = "high"; $dataComplexity = "medium";$cloudProvider = "AWS"; …

Python小工具之httpstat网络分析

一、简介 Python httpstat是一个基于Python的命令行工具&#xff0c;用于测量HTTP请求的性能和状态信息。它能够向目标服务器发送HTTP请求&#xff0c;并显示详细的统计信息&#xff0c;包括DNS解析时间、建立连接时间、TLS/SSL握手时间、首字节时间、总时间等。这些信息对于排…

AI写作有用?未成年不准看巴黎奥运会!——早读(逆天打工人爬取热门微信文章解读)

早上动力AI该作的念头&#xff0c;发觉改完&#xff0c;狗屁不是 引言Python 代码第一篇 洞见 最残忍的社会现实&#xff1a;你能挣多少钱&#xff0c;都是被设计好的第二篇 啦啦啦 开剪辑啦结尾 引言 呀 我们正年轻着 最近觉得有点烦 因为自己有点堕怠 但是呢 越烦越急躁 导致…

网络协议一 : 搭建tomacat,intellij IDEA Ultimate 的下载,安装,配置,启动, 访问

需要搭建的环境 1.客户端--服务器开发环境 客户端&#xff1a;浏览器&#xff08;HTMLCSSJS&#xff09; 服务器&#xff1a;JAVA 1.安装JDK&#xff0c;配置JAVA_HOME 和 PATH 2.安装Tomcat 3.安装IDE--intellij IDEA Ultimate 是旗舰版的意思。 2.TOMCAT 的下载和解…

基于嵌入-对比学习的联邦知识图谱补全

1 引言 1.1 现存问题 在联邦学习中&#xff0c;跨客户端的数据异质性(即非相同分布的数据)是主要挑战&#xff0c;因为当数据异质性存在时&#xff0c;本地目标可能与全局目标不同。 如图所示&#xff0c;School KG中的三元组表示Bob和Jack的学术信息&#xff0c;而ecommerc…

Redis与缓存

文章目录 Redis与缓存一致性问题大Key问题缓存穿透缓存击穿缓存雪崩 Redis与缓存 Redis作为缓存具有高性能、丰富的数据结构和灵活的过期机制等优点。由于Redis将数据存储在内存中&#xff0c;它能提供极低的延迟和高吞吐量&#xff0c;适合用于缓存数据库查询结果、会话数据和…

集成测试:确保软件模块协同工作的关键步骤

目录 前言1. 集成测试的概念1.1 增量集成测试1.2 大爆炸集成测试 2. 集成测试的主要作用2.1 确保模块间正确交互2.2 发现设计缺陷2.3 提高系统稳定性 3. 集成测试在整个测试过程中的地位3.1 从单元测试到集成测试3.2 从集成测试到系统测试 4. 常用的集成测试工具4.1 JUnit4.2 T…