Linux - 第4节 - Linux进程控制

news2024/9/22 3:54:10

1.进程创建

1.1.fork函数

在linux fork 函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。
#include <unistd.h>
pid_t fork(void);
返回值:子进程中返回0,父进程返回子进程id,出错返回-1
进程调用 fork ,当控制转移到内核中的 fork 代码后,内核做:
\bullet 分配新的内存块和内核数据结构给子进程  
\bullet 将父进程部分数据结构内容拷贝至子进程
\bullet 添加子进程到系统进程列表当中
\bullet fork返回,开始调度器调度

当一个进程调用 fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以开始它们自己的旅程。
代码如下图一所示,运行结果如下图二所示,这里看到了三行输出,第一行是执行的fork函数之前父进程的打印代码,第二行是执行的fork函数之后父进程的打印代码,第三行是执行的fork函数之后子进程的打印代码。
可以得出结论, fork 之前父进程独立执行, fork 之后,父子两个执行流分别执行,如下图三所示。注意, fork 之后,谁先执行完全由调度器决定。

问题:对于父子进程的代码部分,是否只有fork之后的代码是被父子进程共享的?

答:我们前面提到进程具有独立性,也就是说进程的代码和数据必须独立,数据的独立我们上一个博客讲过是依靠写时拷贝实现的,代码部分因为是只读的,所以可以默认代码是独立的。一般情况下,fork之后父子共享所有的代码,子进程执行的后续代码不等于共享的所有代码,只不过子进程只能从这里开始执行。

CPU的寄存器中有一个eip寄存器,该寄存器一般被称为程序计数器或pc指针,其功能是保存当前正在执行指令的下一条指令。fork之后,eip程序计数器会拷贝给子进程,子进程便从该eip所指向的代码处开始执行。

问题:fork之后,操作系统做了什么?

答:进程=内核的进程数据结构+进程的代码和数据,fork之后操作系统创建子进程的内核数据结构(struct task_struct + struct mm_struct + 页表) + 代码继承父进程以共享的方式,数据以写时拷贝的方式,操作系统通过这些操作保证了不同进程之间的独立性。

1.2.写时拷贝

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。具体见下图:

注:

1.父子进程的页表都是只读的,当子进程修改内容之后,数据段所对应的父子进程的页表部分会将只读属性去掉,对子进程数据段对应页表部分进行修改。

2.写时拷贝是由操作系统的内存管理模块完成的。
问题:为什么要写时拷贝?创建子进程的时候就把数据分开不行吗?
原因一:父进程的数据,子进程不一定全用,即便使用也不一定全部写入,因此创建子进程的时候就把数据分开会有浪费空间的嫌疑。
原因二:最理想的情况,会被父子修改的数据提前进行分离拷贝,不需要修改的共享即可,但是从技术角度实现复杂,因为代码不跑很难知道要修改哪些变量。
原因三:如果fork的时候就无脑拷贝数据给子进程,会增加fork的成本(内存和时间)
根据以上三个原因,所以最终采用写时拷贝,写时拷贝只会拷贝父子修改的,其实就是拷贝数据的最小成本,并且写时拷贝本质是一种延迟拷贝策略,只有真正使用的时候才开空间进行拷贝,变相的提高了内存的使用率。

1.3.fork常规用法

\bullet 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
\bullet 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

1.4.fork调用失败的原因

\bullet 系统中有太多的进程。
\bullet 实际用户的进程数超过了限制。
子进程创建失败的例子:
代码如下图一所示,利用for循环不停的让父进程fork创建子进程,对于父进程来说,如果id小于0说明子进程创建失败退出循环,如果id大于0则说明子进程创建成功循环继续。对于子进程来说,id等于0子进程创建成功,使用sleep函数和exit函数使得子进程持续两秒就退出,因此子进程不会循环fork。如下图二所示,在输出结果中有子进程创建失败的情况。


2.进程终止

2.1.进程终止的正确认识

问题:在c/c++中,main函数可以认为是入口函数,函数最后都要return或return 0,那么return和return 0是给谁return?一定要return数值0吗,其他值可以吗?

答:常见进程退出有三种情况,第一种代码跑完结果正确,第二种代码跑完结果不正确,第三种代码没跑完程序异常了。main函数的return返回值一般叫做进程退出码,如果return返回值为0代表代码跑完结果正确,如果return返回值为非0代表代码跑完结果不正确,使用不同的非0值代表不同的错误原因。

进程退出码表征了进程退出的信息,前面我们讲过进程退出要进入僵尸状态,僵尸状态的进程必须要被父进程或操作系统回收,读取其退出信息之后进程才会进入x状态释放,因此进程退出码很重要,其是会被父进程或操作系统读取的。因此return返回是给父进程或操作系统return的。

代码如下图一所示,运行该代码,该代码对应进程的父进程是bash进程,此时连续两次使用echo $?命令,如 下图二所示,可以看到第一次运行结果打印123,第二次运行结果打印0。echo $?的功能是打印bash进程中最近一次子进程执行完毕时对应进程的退出码,因此第一次echo $?打印的是下图一代码的退出码,第二次echo $?打印的是第一次echo $?命令的退出码。

系统中的命令如果执行失败,那么该命令的退出码也是非0的,如下图所示。

问题:一般而言,失败的非零值应该如何设置呢?各种非零值默认表达的含义是什么?

答:我们之前学过strerror函数,其功能是将一个错误码转为错误码描述,使用下图一所示的代码,打印1-100错误码对应的错误码描述,打印结果如下图二所示。

从打印结果可以看到0代表成功,1代表权限不允许等等。要注意这里打印的是c语言规定自己的错误码标准,其他语言或系统不一定遵守(Linux操作系统就没有遵守)。

2.2.进程终止的常见做法

方法一:

在main函数中return,进程退出。

注:只有在main函数中return才是进程退出,在其他函数中return不代表进程退出,非main函数return代表函数调用结束。

方法二:

在代码的任意地点中调用exit函数,进程退出。exit函数后面括号中的内容就是退出码,对应main函数return的值。

注:

1.main函数和非main函数调用exit都可以让进程退出。

2.使用exit需要包含<stdlib.h>头文件。

代码如下图一所示,运行该代码,然后使用echo $?命令,打印的结果为111,如下图二所示。退出码为111说明该进程代码没有执行完,在函数fun中就将该进程终止了。

exit和_exit:

_exit和exit功能基本相同,二者的关系是调用和被调用的关系,exit的实现中调用了_exit。

_exit和exit唯一的区别是:exit中止进程并且刷新缓冲区,_exit只中止进程没有任何刷新操作。

exit测试代码如下图一所示,运行结果如下图二所示,运行结果为先停顿一秒然后显示hello word。_exit测试代码如下图三所示,运行结果如下图四所示,运行结果仅为停顿一秒。因此可以看出exit函数刷新了缓冲区而_exit函数没有刷新缓冲区。

注:

1._exit是系统函数,exit是c语言的函数。

2.使用_exit需要包含<unistd>头文件。

2.3.Linux内核对于进程终止的操作

进程=内核结构(task_struct、mm_struct)+进程代码和数据

当一个进程终止时,进程进入z状态,父进程或操作系统读取其退出码等信息,然后将该进程设置为x状态,等待释放其内核结构以及代码和数据。

实际上在进程释放的时候,操作系统一定会将进程的代码和数据部分释放掉,进程的内核结构部分(task_struct、mm_struct)不一定会被释放。创建对象首先要开辟空间,然后要进行初始化,这两步都要花时间,因此重新创建一个进程内核结构部分要花费时间,在Linux中会维护一个废弃的数据结构链表,将要释放的内核结构挂在链表中,当需要创建内核结构对象时,在该链表中拿出来一个然后进行初始化工作即可,节省了开辟空间的开销。这里提到的废弃的数据结构链表就是内核数据结构缓冲池或slab分派器。


3.进程等待

3.1.进程等待的原因

问题:为什么要进程等待?

原因一:解决僵尸进程的内存泄漏问题
子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题, 进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程,这样就会造成内存泄漏。
原因二:获取子进程的退出状态
父进程派给子进程的任务完成的如何我们需要知道。子进程运行完成,结果对还是不对,或者是否正常退出,父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息(退出码等)。

3.2.进程等待的常见做法

方法一:

父进程中调用wait函数,获取子进程退出信息,并将其子进程由僵尸状态转为释放状态。wait函数如果等待成功则返回等待子进程的pid,如果等待失败则返回小于0的值。

代码如下图一所示,运行代码的同时使用while :; do ps ajx | head -1 && ps ajx | grep myproc | grep -v grep; echo "-----------------------------------------------------------------"; sleep 1; done命令作为监控脚本,监控进程状态,代码运行情况如下图二所示。

父进程运行后等待40秒,在这40秒内子进程本应一直处于S运行状态,但在这40秒内我们使用kill -9  命令将子进程杀掉,子进程由S运行状态变为Z僵尸状态,40秒之后父进程调用wait函数获取子进程退出信息并将子进程由z僵尸状态转为释放状态进行释放,此时只剩下父进程,父进程10秒后打印等待成功和wait函数返回的等待的子进程pid,最后父进程退出。

注:

1.wait函数是一个系统调用接口,需要包含<sys/types.h>和<sys/wait.h>头文件。

方法二:


4.进程程序替换

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

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

相关文章

考虑泄流效应的光伏并网点电压系统侧增援调控方法matlab

目录 1主要内容 1.1 泄流效应​编辑 1.2 候选无功补偿站优选方法 1.3 算法步骤 2部分代码 3程序结果 4程序链接 1主要内容 程序主要复现《考虑泄流效应的风电场并网点电压系统侧增援调控方法_于其宜》&#xff0c;将光伏取代风电&#xff0c;考虑某时刻光伏并网的电压增…

3年工作之后是不是还在“点点点”,3年感悟和你分享....

经常都有人问我软件测试前景怎么样&#xff0c;每年也都帮助很多朋友做职业分析和学习规划&#xff0c;也很欣慰能够通过自己的努力帮到一些人进入到大厂。 2023年软件测试行业的发展现状以及未来的前景趋势 最近很多测试人在找工作的时候&#xff0c;明显的会发现功能测试很…

死磕JAVA10余年!手写“Java核心技能精选”Github一夜疯涨30w+

写在前面 想在面试、工作中脱颖而出&#xff1f;想在最短的时间内快速掌握 Java 的核心基础知识点&#xff1f;想要成为一位优秀的 Java 工程师&#xff1f;本篇文章能助你一臂之力&#xff01; 很多同学对一些新技术名词都能侃侃而谈&#xff0c;但对一些核心原理理解的不够…

很好用的 UI 调试技巧

文章目录 UI调试效果(一)评论最后UI调试小姑(二)参考文档 很好用的 UI 调试技巧 UI调试效果(一) javascript: (function() {const style = document<

RT-Thread初识学习-02

课程链接 02-RT-Thread介绍_哔哩哔哩_bilibili 学习方法 使用官方资料进行学习&#xff0c;并且在学习的过程中与FreeRTOS进行比较 RT-Thread API参考手册: 基础定义 标准版RTT移植 这里的串口2是由于打印信息的&#xff0c;因此你需要在开发板上选择USB-TTL串口&#xff0…

什么是品牌控价?品牌控价的意义是什么?品牌控价合不合法

很多人不明白为什么要控价&#xff0c;今天我们就来聊一聊品牌控价。 一、 什么是控价 顾名思义&#xff0c;“控价”就是管控价格&#xff0c;将价格控制在合理的范围以内。 品牌方生产出产品&#xff0c;要以一定的价格投入市场。而市场中的实际成交价格会受渠道各因素的影…

Kubernetes二 Kubernetes之实战以及pod详解

Kubernetes入门 一 Kubernetes实战 本章节将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其进行访问。 1.1 Namespace Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。…

pmp考试是什么?适合哪些人学?含金量?(含pmp资料)

先说一下我这个人的理解&#xff0c;PMP就是提高项目管理理论基础和实践能力的考试。 再说说PMP官方一点的说明&#xff1a; PMP证书全称为Project Management Professional&#xff0c;也叫项目管理专业人士资格认证。PMP证书由美国项目管理协会(PMI)发起&#xff0c;是严格…

覃小龙34岁生日记:结合趋势,发挥优势,方能百战不殆

覃小龙34岁生日记:结合趋势&#xff0c;发挥优势&#xff0c;方能百战不殆&#xff01;2023-2-20星期一 覃小龙2023年2月17日&#xff0c;是我34岁生日&#xff0c;1989年出生的我&#xff0c;一晃眼&#xff0c;已经走过第34个年头了&#xff01;从2016年创业到今天&#xff0…

RK3568存储性能测试

USBU盘储存性能参数(USB3.0接口)参数测试条件最小典型最大单位说明写速度写入1GB数据—32.6—MB/sU盘型号&#xff1a;KODAK&#xff0c;32GB USB3.0读速度读取1GB数据—66.7—MB/s 备注HW356X-CORE-4GB-32GBHW356X-GKA&#xff0c;操作系统&#xff1a;LinuxU盘储存性能参数(U…

linux 系统编程之线程

线程 文章目录线程1 线程概念2 NPT安装线程 man page&#xff1a;查看指定线程的 LWP 号&#xff1a;3 线程的特点4 线程共享资源5 线程非共享资源6 线程的优缺点7线程常用操作1 线程号pthread_self函数&#xff1a;pthread_equal函数:参考代码2 错误返回值分析参考代码3 线程的…

搞懂Druid之连接创建和销毁

前言 Druid是阿里开源的数据库连接池&#xff0c;是阿里监控系统Dragoon的副产品&#xff0c;提供了强大的可监控性和基于Filter-Chain的可扩展性。 本篇文章将对Druid数据库连接池的连接创建和销毁进行分析。分析Druid数据库连接池的源码前&#xff0c;需要明确几个概念。 …

【大数据离线开发】7.2 搭建HBase环境

7.2 搭建HBase的环境 准备工作&#xff1a; 解压Hbase安装包 [rootbigdata111 tools]# tar -zxvf hbase-1.3.1-bin.tar.gz -C ~/training/设置Hadoop的环境变量 vi ~/.bash_profile HBASE_HOME/root/training/hbase-1.3.1 export HBASE_HOMEPATH$HBASE_HOME/bin:$PATH export…

37、基于51单片机乒乓球比赛系统设计

摘要 乒乓球游戏电路是一个对输入信号、输入时机正确与否的8个LED表示乒乓球球台和乒乓球&#xff0c;用数码管模拟显示器&#xff0c;显示比赛局数比分和每局玩家得分的电路。电路并不复杂&#xff0c;整体分为两个模块&#xff1a;一&#xff0c;游戏主模块&#xff1b;二&a…

excel图表技巧:如何制作自动刷新的动态喜报

临近年关&#xff0c;各企业进入节日营销大战&#xff0c;每天都需要对销售数据进行统计分析&#xff0c;同时为了鼓励及带动新品的销售气氛&#xff0c;还会制作鼓励销售人员士气的喜报。今天就来分享使用Excel如何快速制作可以自动更新数据的喜报&#xff0c;非常方便哦&…

c语言编程规范 第四部分

5、禁止头文件循环依赖头文件循环依赖&#xff0c;指a.h包含b.h&#xff0c;b.h包含c.h&#xff0c;c.h包含a.h之类导致任何一个头文件修改&#xff0c;都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。而如果是单向依赖&#xff0c;如a.h包含b.h&#xff0c;b.h包含c.h&a…

单例模式设计(面试题)

1、static修饰变量规则static修饰的静态成员属于 类而不是对象&#xff0c;所有的对象共享一份静态成员数据&#xff0c;所以不占用类的空间static修饰的成员&#xff0c;定义类的时候&#xff0c;必须分配空间static修饰的静态成员数据 必须类中定义 类外初始化静态成员变量可…

CentOS7安装MariaDB步骤

文章目录1.配置MariaDB yum源2.安装MariaDBMariaDB数据库管理系统是MySQL的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可。 MariaDB的目的是完全兼容MySQL&#xff0c;包括API和命令行&#xff0c;使之能轻松成为MySQL的代替品。 CentOS 6 或早期的版…

0基础成功转行Python自动化测试工程师,年薪30W+,经验总结都在这(建议收藏)

两年前的决定我觉得还是非常正确的&#xff0c;就是自学了python&#xff0c;然后学习了自动化测试、性能测试、框架、持续集成&#xff0c;同时也把前面的软件测试基础知识全部补全了。目前的收入还比较满意&#xff0c;月入2W&#xff08;仅代表个人收入&#xff09;,13薪&am…

技术团队管理要求 网文节选要点,内部培训用

业务线开发级别分布 技术开发 高级技术开发 技术专家 p6p7 团队专家 p7 单团队 10人小团队 领域专家 p8 多团队 2-5 10人小团队&#xff0c;技术顶峰&#xff0c;业务和管理能力都不能弱。 商业或者业务leader p8 p9&#xff0c;商业模式设计和商业成功。业务能力和管…