Linux系统编程第五节——进程创建、终止、等待(通俗易懂快速上手版本)

news2024/11/18 23:48:00

目录

进程的创建

写时拷贝

进程的终止

进程的等待

状态参数status

wait函数和waitpid函数


我们本节内容,主要来讲述进程控制有关的内容。

同样,我们会用通俗易懂、不同于教科书的讲授思路,来为大家讲解。

同时,本节内容板块清晰简明,在最终同学们的思维导图可以做起来呦~~~

(同时需要说明一下,我们本节注重的是系统编程方面,而不是完完全全地侧重于系统理论知识呦,如果想要深入学习进程的知识,可以参考以后的《操作系统》篇章,敬请期待哈~)

本节导图:

 

进程的创建

进程是如何创建出来的?

实际上,进程的创建理论上都是由在另一个进程里创建出来的。

就好像是细胞分裂一样,子细胞怎么来的?由父代细胞分裂而来的。那子进程是怎么来的?同理,是由父进程创建的。最初的那个细胞叫做受精卵(就是老祖宗),那最初的那个进程是什么呢?通常是一个系统进程(通常为1号进程)(用户没有控制的权限),它可以理解为是你在系统开机的时候启动的进程。之后系统上所有的进程,都是由父代而来。

那,我们自己如果想写一个程序来创建和控制进程,我们应该怎么样来去做呢?

答案就是用Fork函数

我们通常用fork函数来创建新的进程。

//函数解释 fork

pid_t fork(void ); 

具体的函数说明(在Centos 7中通过在命令行中: man fork得到 ):

 

同时,从上述的手册中可以看出,在程序调用fork的时候,是以父进程为模板的。准确来说,就是复制一份父进程的除了信号、锁等的其他一切东西。比较常见的,有父进程的虚拟进程地址空间、PC(程序计数器)、已经PCB里其他的有关数据结构和数据等。

用比较标准的话来说,就是以父进程的数据结构和相关数据为模板,拷贝一份新的进程。

 还需要注意的是,该函数是有两个返回值的。

一个是父进程的返回值,一个是子进程的返回值。

在父进程中,返回的是子进程的ID,在子进程中返回0。如果出错,会返回-1。

为何会有两个返回值?这是因为该函数是用来创建进程的,而在进程创建之前,我们的子进程就已经创建好了。而子进程和父进程的PC(即程序计数器)拥有相同的值,即它们从相同的位置开始执行。所以在返回之前,父子进程同时在执行、调用fork函数。所以,在fork函数返回的时候,也是会有两个返回值的。

从微观角度来解释的话或许更加容易理解上述过程:从微观来说,就是从程序运行的角度来说,可以分为这样几个过程:

1、分配新的内存块和内核数据结构给子进程
2、将父进程部分数据结构内容拷贝至子进程
3、添加子进程到系统进程列表当中
4、fork返回,开始调度器调度

所以说,还是那句话,创建了一个子进程,就是复制了一份和父进程相同的(部分不继承的东西除外)数据结构和数据。

对于虚拟地址空间和物理结构的映射的关系,就涉及到了另一个概念:写时拷贝。

我们来说说:

写时拷贝

父子进程在一开始拷贝过后,会有两个虚拟进程地址空间(父子进程各一个),两个页表。但是它们在物理内存中所映射的区域是同一块(如下图所示)。

 

父子进程如果对这块区域的内容只是读取,而不进行写入(或者说是更改)的操作话,父子进程将始终映射到同一块物理空间上去(即上图所示)

但是如果父进程或者子进程对这一块区域的内容进行了写入更改操作的话,那么操作系统就会对写入更改的数据进行写时拷贝。即将会在其他的地方重新开辟一块空间,将现有的数据拷贝过去,并对新开辟的空间进行写入操作,同时,页表的映射关系也会随之改变(即映射到新的物理地址上去)(如下图所示):

 

看到这里,想必你应该对写时拷贝的特点有了了解了。

 

那么,我们来稍稍总结下它有什么样的特点,以及我们为什么需要写时拷贝?

首先说后面的问题:我们为什么需要写时拷贝?

1、保证父子进程的 “ 独立性 ”。不要存在一种bug的情况:父进程要写个内容,把子进程的数据也给改了。进程之间是有着严格的独立性的。

2、如果是在创建进程的时候直接拷贝,而不是在需要写的时候才进行拷贝,有可能会浪费系统资源。因为不一定是所有的数据都是需要写或者更改的。而不过你不需要写或者不需要更改,那你拷贝就没有意义了。父子进程在物理空间上完全可以共用一块空间。

3、由(2)引出,如果不是在需要写的时候再进行拷贝,那么fork的效率将会变低。因为一次fork有可能在物理空间上也需要拷贝大量的数据。这样的话,就更有可能会导致fork失败。

那再来稍稍总结一下写时拷贝的特点及意义吧:

1、写才拷贝,不写不拷贝。

2、保证了父子进程的独立性。

3、提高的效率,减少了不必要的系统资源的浪费。

进程的终止

在这一部分,退出码是什么、有什么用。以及我们需要区分一下:exit、return和_exit三者之间的区别。

我们先说退出码:

退出码,就是进程终止的状态码。状态码是几,一般是人为规定的。比如我们一般规定退出码为0的时候,表示正常退出。

我们在main函数里的return 0,这里的0,就是退出码。因为在用户的角度来说,执行完return 0之后,该进程就结束了。

我们的程序,执行的结果按照是否出错(指能否运行起来)、是否正确来划分一般会有三种情况:

1、程序未出错,结果正确;

2、程序未出错,结果不正确;

3、程序出错,结果不正确。

(因为程序出错,结果肯定不会正确,所以不存在 程序出错,结果正确 这样一种情况

所以,如果我们的程序未出错,我们可以通过设置退出码的方式,来表示结果是否正确,这样,我们在进程退出后,直接查看进程退出的退出码就可以了。

同时,通过查看进程退出的状态码,我们还能够准确定位到出错的地方是在什么位置。

比如,我们可以有这样一段代码:

 

如图所示,我们说过,在main函数里的return值,就可以认为是进程的退出码。那么如果说,我的b为0时,我的退出码就被设置成了1。相反,在程序运行完后,倘若我查看我的退出码是1,我就能够知道我的错误是除数b被设置为0了。

我们说完了退出码,再来说说exit、return和_exit这三兄弟。其实它们的区别很明显,也很好区分。

1、return:一般来说,是一个函数的返回值,也就是说,遇到return 的时候,表明我这样一个函数过程结束了。但是前面说过,如果是main函数的return , 表示main函数这样一个过程结束。main函数结束,我们也就可以认为整个程序运行结束。它的退出码也会被设置成为main函数的返回值。

2、_exit:直接干掉整个进程

3、exit:它不仅会结束掉整个进程,还会进行资源回收处理等等“擦屁股”的动作。它会执行用户的有关清理函数(比如析构函数等),然后把缓冲区刷新、输入输出流等关闭。然后再调用_exit,向内核释放杀死进程的信号,干掉整个进程。

需要说明一下的是,我们这里的杀死进程,在内核当中,它并不一定是真的把该进程相关的资源(如pcb)等全部释放了。它通常可以采用一种“假释放”的方式:可以通过某一种方式,把该pcb的状态设置为“不用”,或者将该pcb的进程地址空间设置为“无效”的状态,然后取消和该进程有关的连接关系。然后下一次,在需要fork进程的时候,我们就直接可以用这些没有用的、但是已经创建出来的pcb就可以,把相关的属性设置回来即可。这样做,也可以大大提高fork的效率。

进程的等待

我们为什么要有进程等待?或者说,进程等待有这样一种必要吗?

答:有必要。

用比较官方、正式的来说,有如下三点原因:

1、回收僵尸进程,解决内存泄漏


2、需要获取子进程的运行结束状态 ( 这点不是必须的)

3、父进程要尽量晚于子进程退出,可以规范化进行子进程的资源回收、处理业务。

关于第一点,我们可以多说一嘴:

当fork之后会创建子进程,如果子进程挂掉或者退出,父进程不管的话,就会变成僵尸进程,一直存在系统中,从而造成内存泄漏。

因为变成僵尸进程,就是杀不死的状态,kill -9也无能为力,因为无法去杀掉一个已经死了的进程。所以父进程要知道子进程是正常退出,还是运行完成,结果的对与不对。需要对子进程进行等待和回收,需要给子进程擦屁股。

状态参数status

它是一个输出型参数,关于它怎么用,我们一会儿来说。我们先来说它的性质:

它实际上可以看作是一个十六位的位图:

 如果有一个进程正常退出、正常终止,那么其0-7位都是数值0,然后在高8位(即8-15位)填充退出状态码;

如果该进程是被某个信号所杀,而信号一般情况下也都是有编号的,那么就会在低7位(0-6位)来填充该信号的编号,高8位不用,然后第8位用来填充是否生成core dump文件。(1表示生成,0表示不生产)

何为core dump文件?关于core dump文件可以查看一下这篇文章,看完后应该会有所收获。一文读懂 | coredump文件是如何生成的 - 腾讯云开发者社区-腾讯云 (tencent.com)

那么该参数是做什么用的呢?

wait函数和waitpid函数

我们在命令行输入

man 2 wait

能够看到关于wait函数的相关介绍:(如下图)

与此同时,我们可以看到waitpid也显示出来了,与此同时显示出来的还有waitid

 从上面可以看到,它的头文件是两个

我们先来说wait函数。

它的返回值是pid_t,即进程的pid;含义为如果等待成功,则返回被等待进程的pid;否则返回-1.

注意到其有一个参数status,该参数就是我们上面说到的参数。它的类型为int*。

需要注意的是,该参数是一个输出型参数,不是一个输入型参数。什么叫输出型参数?就是函数调用结束以后,会将参数的值写到这个变量里。

换句话说,这个status是用来接收的,本质上不是用来传参的。我们把我们的status定义好了之后,放到该函数里,作为参数传递过去,函数调用完后,操作系统就会把status的值自动填充好,然后还给我们。实现的原理很简单,因为其用的是指针,传递的是变量的地址。倘若我们不关心这个status状态,那么直接传递NULL即可。

我们接下来给出一个例子:

然后我们来运行一下:

运行结果如下图所示 : 

这段代码的含义就不用再过多赘述了,结合注释,还是比较清晰明了的。

我们再来说说waitpid方法:

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

返回值:

1、当正常返回的时候waitpid返回收集到的子进程的进程ID;

2、如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

3、如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

参数:

1、pid:
        如果pid=-1,等待任一个子进程。与wait等效。        
        如果pid>0.等待其进程ID与pid相等的子进程。

2、status:同wait();

3、options:WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待,即非阻塞式等待。倘若为0,则为阻塞式的等待。

关于非阻塞式等待的用法,我们可以使用轮回询问的方式,即使用循环的方式,不断的询问子进程此时是否退出。而非阻塞式的等待使得父进程在子进程运行时,自己可以不用傻傻的等着,也可以做自己的事情。

好,我们本节的内容就暂时到这里。

如果觉得干货慢慢,不妨点个赞,手有余香~~~

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

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

相关文章

你了解你的身体吗?- 基因社会

关于作者 本书的两位作者分别是以太•亚奈和马丁 • 菜凯尔,前者是哈佛大学髙级研究学者, 任职于纽约大学,是生物化学和分子药理 学的教授;后者是杜塞尔多夫海因西里•海 涅大学的生物信息学教授。两位作者从基 因之间合作和竞争…

[附源码]计算机毕业设计的4s店车辆管理系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

5款十分好用,但是没有什么知名度的软件

随着网络信息技术的发展,越来越多的人在办公时需要用到电脑了。如果你想提高办公效率,那么就少不了工具的帮忙,今天给大家分享5款办公必备的好软件。 1.数据可视化软件——Power BI Power BI是一款出色的业务分析软件。Power BI主要是用于在…

[Go] go基础4

1. 并发编程 1.1 并发和并行 并发: 多个线程在同个核心的CPU上运行.并发的本质是串行. 并行: 多个线程在多个核心的CPU上运行. 1.2 协程和线程 协程: 独立的栈空间,共享堆空间,调度由用户控制,本质上有点类似用户及线程,这些用户及线程的调度也是自己实现的. 线程: 一个线…

[附源码]JAVA毕业设计网络饮品销售管理系统(系统+LW)

[附源码]JAVA毕业设计网络饮品销售管理系统(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目…

全新社交电商模式来袭,消费增值结合共享经济完成消费升级

大家好,我是林工,不知道大家是否了解消费增值?这是一个消费储量为基础的理念,体现的是消费者的消费与回报问题,普遍的消费返利,消费全返渐渐地已经不能够满足目前的客户,也就有了一个满足与这部…

【嵌入式硬件芯片开发笔记】4-20mA DAC芯片AD5421配置流程

【嵌入式硬件芯片开发笔记】4-20mA DAC芯片AD5421配置流程 16位、串行输入、环路供电、4 mA至20 mA DAC 可用于HART协议相关电路 同AD5700配合使用 AD5421的SPI和普通的不一样 回读时要发两段 CS中间拉高一次 数据在SCLK上升沿逐个输出,而且在 SCLK下降沿有效 固CP…

使用方法丨艾美捷Caspase-1活性分析试剂盒介绍

如何动态检测活细胞内的Caspase-1的活性,做更真实的实验?艾美捷推荐Immunochemistry Tech(ICT)的FLICA系列科研工具,轻松检测活细胞Caspase-1 活性。 艾美捷Immunochemistry Caspase-1活性分析试剂盒原理&#xff1a…

Qt第三十四章:总结【隐藏标题栏边框、隐藏背景、窗体透明】

目录 隐藏标题栏边框 ①隐藏标题栏代码: ​编辑②自定义标题栏(可以直接Copy) 使用 隐藏背景 ①隐藏背景代码,此时背景上的样式都是无效的。 ②自定义背景,通过重写paintEvent事件来完成 中间绘制的部分是我们想要的,只需要将标题栏边框隐藏掉就可…

五、卷积神经网络CNN5(图像卷积与反卷积)

图像卷积 首先给出一个输入输出结果那他是怎样计算的呢? 卷积的时候需要对卷积核进行 180 的旋转,同时卷积核中心与需计算的图像像素对齐,输出结构为中心对齐像素的一个新的像素值,计算例子如下:这样计算出左上角(即第…

【畅购商城】内网穿透之EchoSite

目录 概述 注册用户 抢注域名 ​​​​​​​下载客户端 ​​​​​​​编写配置文件 ​​​​​​​启动 ​​​​​​​访问 ​​​​​​​概述 EchoSite一款收费的内网映射工具(已下架) 花生壳:内网穿透工具,免费版…

springboot集成Lombok、MybaitsPlus、SwaggerUI

springboot集成Lombok、MybaitsPlus、SwaggerUI 基础环境&#xff1a;JDK8或者JDK11版本 Maven3.5(采⽤默认) IDEA旗舰版 Mysql5.7以上版本 创建springboot项目 在线构建⼯具 https://start.spring.io/ 修改pom.xml中内容 <!-- 代码库 --> <repositories> &l…

如何提高量化策略回测的效率

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

教你轻松设计圣诞节日活动的邀请函?

即将迎来一年一度的圣诞活动&#xff0c;商家们要如何对此次活动展开宣传呢&#xff1f;要如何制作出一张符合节日气氛的活动邀请函&#xff1f;下面小编就教你如何使用在线工具乔拓云&#xff0c;用在线邀请函模板设计活动邀请函&#xff0c;一键就能生成活动邀请函链接&#…

springmvc整体运行流程

请求处理的流程 1&#xff1a;浏览器发送请求送至前端控制器DispatcherServlet。 2&#xff1a;DispatcherServlet收到请求后调用HandlerMapping处理器映射器。 3&#xff1a;处理器映射器找到具体的Handler处理器&#xff0c;封装成为执行链 4&#xff1a;返回执行链给Disp…

SpringBoot+MyBatis多表查询:以点餐系统的订单管理为例

文章目录项目场景数据库设计POJODaoServiceTest运行结果问题及解决项目场景 SpringBoot MyBatis &#xff0c;实现点餐系统的订单查询。 参考&#xff1a;SpringBootMyBatis多表联合查询 数据库设计 通常一个订单中会包含多个菜品&#xff0c;即一条 order 里含多个 item&am…

使用 Zotero Citation Counts Manager 自动获取文献引用数

前言 最近习惯了搜完文献把文献的引用贴进 Zotero 文献条目的 Note 里&#xff0c;但是自己一点一点打字太累。想到了 Zotero 有插件&#xff0c;简单调研一下&#xff0c;发现了一个可以用的插件。支持 CrossRef 和 SemanticScholar 的引用数获取。&#xff08;相对来说个人比…

QT QSlider、QHorizontalSlider、QVerticalSlider 控件 使用详解

本文详细的介绍了QSlider、QHorizontalSlider、QVerticalSlider控件的各种操作&#xff0c;例如&#xff1a;新建界面、设置刻度显示、设置范围值、设置值、获取值、设置步长、刻度间隔、改变方向、滑动信号、按下信号、滑动信号、释放滑块、样式表等操作。 本系列QT全面详解文…

职业生涯交叉点,7年测试工程师经历,继续做测试还是转开发?

我毕业后一直从事软件测试工作&#xff0c;今年28岁了。所做的工作都是功能测试&#xff0c;对于性能测试、自动化测试完全没有接触。 我是在深圳的一个小公司上班&#xff0c;每天朝九晚五的&#xff0c;工作不累。属于那种要来活了半天就可以搞定&#xff0c;剩下的时间都是…

三车道交通流元胞自动机研究附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …