【Linux操作系统】进程控制

目录

  • 一、进程创建
    • 1.1 认识fork
    • 1.2 写时拷贝
  • 二、进程终止
    • 2.1 进程退出
    • 2.2 函数退出
    • 2.3 exit
  • 三、进程等待
  • 四、程序替换

一、进程创建

1.1 认识fork

fork函数是系统调用接口,用来创建子进程的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据进程的pid,可以看出父进程fork后分为父进程和子进程,分开后的父进程就是原来的自己,然后多了一个子进程。父进程的父进程是bash
在这里插入图片描述

那么fork之后多创建一个子进程有啥用呢?既然多了一个进程,肯定是要做事情的,父进程一个不够,让子进程去做,同时父进程去做另一件事。怎样让它们同时各自做不同的事情?fork是有返回值的,让返回值对接下来的代码进行分流,给父进程和子进程不同的任务。
在这里插入图片描述

现象:
在这里插入图片描述
给父进程的id是子进程的pid,给子进程的id是0,为什么?后面再谈论

父子进程各自做不同的事情,验证:两个while循环:

在这里插入图片描述
在这里插入图片描述
两个进程可以同时进行,为什么?分析原理:进程是等于内核数据结构(PCB)+ 可执行程序(代码和数据),在fork之前,父进程有自己的PCB和代码数据,fork之后,该函数会多创建一个子进程,这个子进程也同时会有PCB,它是以父进程为模板创建的。那代码和数据呢?首先要清楚的一点是:代码和数据都是父进程提供的。也就是说子进程运行的代码是父进程给的,父子进程共享父进程的代码和数据。那它们两个执行不同的事情是怎样的呢?根据返回值id,id为0是子进程的执行流,id大于0,是父进程的执行流,父进程的代码被分开同时执行。还有一点,CPU只要遇到运行起来的进程,不管是谁,都是可以同时进行的(同时打开浏览器、音乐、游戏等)。总结一下就是:fork之后,代码共享父进程的

fork返回值的问题:

一、给父进程的id为什么是子进程的pid,给子进程的id为什么是0?

父进程与子进程是一对多的关系,即一般一个父进程有n个子进程,父进程要找到某个子进程对它进行控制等操作的话,必须要有该子进程的pi信息,否则怎么找到要找的子进程;而父进程只有一个,子进程找父进程是唯一的,所以返回0即可。

二、两个进程能同时执行,说明id从fork函数那里返回的有两个值,以前我们的认识是一个函数一个返回值,为什么fork有两个返回值呢?

fork函数的作用是多创建一个子进程(也可以创建多个),在其函数内部的代码中就已经实现好了,也就是说,父进程和子进程在fork函数内部就已经分流了,各自执行不同的任务,所以也就可以返回两个返回值,父进程返回父进程的id,子进程返回子进程的id

三、就算有两个返回值,可是只有一个变量id,为什么一个id既可以等于0,又可以大于0?

与进程地址空间有关,进程之间是具有独立性的,互不影响对方。

1.2 写时拷贝

为什么父子进程代码共享?

本质是通过页表指向物理内存同一块区域。磁盘中的可执行程序加载到内存,物理内存开辟空间放代码和数据。父进程在地址空间申请的虚拟地址,代码区的的虚拟地址通过页表的映射关系找到物理内存的代码,数据区同理。fork之后,子进程是被按照以父进程位模板创建的,所以地址空间和页表是以拷贝发方式给子进程,父子进程的虚拟地址是相同的,页表也是,在没有对一方进行写入的情况下,默认子进程的地址空间的虚拟地址通过页表指向的是前面父进程在物理内存中开辟的代码和数据,所以父进程和子进程共享代码。

在这里插入图片描述

如果对子进程重新写入,会发生写时拷贝,父子进程各自的一份数据
在这里插入图片描述

为什么要有写时拷贝?

1.为什么子进程被创建,父进程不直接把数据给子进程?主要有两个原因:资源问题和成本问题。假如一个子进程创建出来后,用户并没有使用它,或者是没有完全使用,那么如果子进程被创建要单独给它数据的话,不就是资源浪费了吗,所以默认先让子进程与父进程的资源共享,当需要用子进程时,再按需申请资源。如果每次创建的子进程都要有自己的数据,创建成本增加,更何况有时候该子进程没有被使用。2.写时主要是修改,申请的空间拷贝父进程的数据,对数据重新进行写入,有了写时拷贝可以增加程序运行确定性,除了申请空间的位置不一样,其他的是一样的,这样可以提高使用性。

如何做到写时拷贝?

该过程与页表有很大的关系。首先,页表不仅有前面说的只放虚拟地址和物理地址,还有很多选项,其中有一个选项是权限,r、w、rw。看以下代码,我们输入一个字符串,然后对它的首字符修改,结果运行出错,不能修改。原因:从语言上的角度是,该字符串在常量区,具有常属性,不能被修改。在操作系统的角度是,该字符串常量其实是虚拟地址,对字符串的首字符修改,也是虚拟地址,修改就是写入,这个过程必离不开虚拟地址到物理地址的转换——通过页表,但是页表上表示该虚拟地址的权限是只读,也就是不能写入,所以操作系统就不让用户修改。

在这里插入图片描述

为什么数据段是只读?

fork后子进程被创建,数据段是只读,那么转换就会出问题,这个就是缺页中断,于是操作系统就会采取措施,解决这个问题。只要有一方有写入,操作系统就会把页表中权限选项改为读写,此时就可以进行写入了。也就说有转换的问题,即缺页中断,因为是只读的,操作系统知道这个情况,就会发生写时拷贝,重新开一块空间给子进程,同时将权限变为读写。(告诉操作系统有进程要写入了,让操作系统发生写时拷贝;怎么告诉操作系统,因为某一方有写入,但权限是只读,页表转换出现问题,即缺页中断,此时这个消息会给操作系统;操作系统的做法:写时拷贝,在物理内存新开空间连同父进程的数据给子进程,子进程可以重新写入数据,同时页表的权限改为读写,修改权限是在子进程重新写入数据之前已经做好工作了)

fork失败原因: 一、系统中有太多进程;二:实际用户的进程数超过了限制

二、进程终止

2.1 进程退出

main函数的返回值,叫做进程的退出码。一般情况下0表示进程执行成功,非0表示失败。非0表示失败的错误码比如:1、2、3、4、5等,不同的数字表示不同的错误原因。可以使用echo $?查看退出码:后面一次的退出码是0表示该指令执行成功,它的默认退出码是0
在这里插入图片描述
在这里插入图片描述
错误码要转化为错误描述。 有两种:一是语言和系统自带的方法,转化为错误码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二是自定义:
在这里插入图片描述
在这里插入图片描述
main函数return,表示进程退出;其他函数退出,表示该函数调用完毕

2.2 函数退出

errno查看函数的执行情况——成功、失败、错误原因。只读不会在当前目录创建新的文件
在这里插入图片描述
在这里插入图片描述
所以进程退出的情况有三种:进程代码执行完,结果是正确的、不正确的和未执行完,进程出异常的。进程出异常的本质是收到了异常信号,每个信号都有自己的编号,不同的信号编号表示异常的原因,下面见见信号:
在这里插入图片描述
其实评估一个进程的最终情况,只要看两个数字,一个是信号编号,另一个是退出码,对应前面的三种情况:结果正不正确看退出码,有没有异常看信号。只要信号异常,不管结果正不正确都不能正常执行。

2.3 exit

查看接口信息:
在这里插入图片描述
可以使进程终止,参数是退出码;在任何地方调用,都可以终止进程
在这里插入图片描述
在这里插入图片描述
除了exit库函数,还有一个叫做_exit的系统调用接口,它的功能和前者基本类似,不同的是exit会支持刷新缓冲区,_exit不会。通过代码看现象:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

exit其实是_exit封装的库函数

三、进程等待

为什么要有进程等待?

  1. 子进程退出,如果父进程不管,子进程变僵尸,导致内存泄漏问题
  2. 回收子进程资源,获取退出信息

wait函数有两个,两个差不多是一样的,只是参数数量不同。
在这里插入图片描述
下面看看wait函数父进程回收子进程资源:wait的参数先设置为NULL
在这里插入图片描述
在这里插入图片描述
fork之后,谁先运行不确定,由调度器决定。但是最后一个退出,一定是父进程,因为它要回收子进程的资源。

获取子进程退出信息,同时解决僵尸:使用waitpid,参数中的pid解释如下,这里我们的代码直接用id来表示,第二个参数是输出型参数,获取退出信息。
在这里插入图片描述
在这里插入图片描述

获取status:
回收的子进程就是fork后父进程创建的子进程,rid表示的就是子进程的pid;但是status退出码为什么是256?因为status是局部使用的,有自己的格式,根据exit(1),所以退出码是1,格式如下。
在这里插入图片描述

1️⃣通过位运算来获取子进程status:
在这里插入图片描述
在这里插入图片描述

2️⃣通过宏获取子进程status:
在这里插入图片描述
在这里插入图片描述

可以通过变量获取子进程的退出信息吗?

不能,因为进程具有独立性,父子进程改了对方的数据之后,无法看到对方的数据。前面说过,退出信息主要是两个:进程退出码和信号编号。这两个是数据是放在进程的PCB对象中,PCB对象由操作系统管理,也就是说,要得到数据必须通过访问操作系统,访问操作系统必须通过系统调用接口来实现。

阻塞等待与非阻塞等待
调用wait和waitpid的三种情况:

  • 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获取退出信息
  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
  • 如果不存在该子进程,则立即出错返回

当子进程还在运行时(子进程还没结束,结束后再由父进程回收),父进程在做什么?阻塞等待。与前面的进程状态中的阻塞相似,父进程在等待子进程结束,它什么也没做,只是单纯的等,此时父进程把自己的状态设置为S睡眠状态。

非阻塞等待
子进程正在运行,父进程通过系统调用(waitpid)访问子进程,子进程没有结束,返回值为0,告诉父进程子进程还在运行中,然后再访问,以此循环,多次访问。直到某一个访问子进程运行完了,父进程获取子进程的退出信息。注意,阻塞是一直正在访问,即一次访问,父进程一直在等待,没有做其他事情。但是非阻塞等待,父进程访问次数有多次,只要每次访问完子进程还没结束,父进程可以去做别的事情,不会干等。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、程序替换

程序替换原理(什么是程序替换)

一般来说,我们自己写的程序,执行这个程序执行的是自己的代码。但是如果我们创建的程序想执行其他程序的代码行不行?其实是可以的,通过程序替换可以执行别的程序的代码。过程:磁盘中有多个可执行程序,比如程序A,是我们自己写的;程序B,是系统自带的(例如指令ls,指令运行起来也是进程)。程序A的代码和数据对应放在物理内存中的代码段和数据段,如果程序A要执行程序B的代码和数据,核心工作是将程序B的代码和数据在物理内存中覆盖程序A的,然后相应的虚拟内存的区域大小也会调整,页表重新建立映射关系,CPU调度的时候就可以做到执行程序A,但代码是程序B的,也就执行程序B了。注意:替换过程中没有创建新的进程

在这里插入图片描述

怎么替换? 通过系统调用接口。在物理内存中覆盖数据和代码是操作系统做的,要知道操作系统的工作后数据必须要通过系统调用接口——exec*
在这里插入图片描述

先来第一个execl,它的第一个参数是程序的路径,第二个是参数是说明程序如何执行,第三个参数是可变参数。第二个参数是程序名称,后面的可变参数是选项,所以命令行怎么写,参数怎么传。注意,不管参数有几个,参数最后一个是NULL,不是"NULL"。
在这里插入图片描述
在这里插入图片描述

细节1:只要替换成功,那么exec* 后续的代码就不会执行。细节2:exec* 只有失败返回值,没有成功返回值。细节3:替换完成,不会创建新的进程。细节4:可以按非标准传参,但是尽量用标准传参。

创建一个进程,先PCB、页表、地址空间还是先把程序加载到内存?

先前者,因为就算先把程序加载到内存,PCB对象的属性和页表的映射关系都没有准备好。如果是是前者先,即使没有把程序加载到内存,当用户有请求的时候,操作系统通过缺页中断在内存中把程序加载进来,然后页表再重新建立映射关系,进程就拿到了代码和数据。

程序加载是什么?为什么?怎么做的?

程序加载是指把程序加载到内存中去。因为是冯诺依曼体系规定的。程序替换。

多进程版本
通过代码观察现象:多创建一个子进程,父进程等待,子进程执行中程序替换
在这里插入图片描述
在这里插入图片描述

父进程可以拿到执行结果,并没有像子进程那样被其他程序替换掉。子进程被创建时它的页表指向的代码和数据和父进程是一样的(默认情况下),但是要进行程序替换,此时内存中发生写时拷贝,不仅数据拷贝了,代码也拷贝了,父进程还是原来的代码和数据不影响,子进程的代码和数据被其他程序替换了。所以总结下:进程具有独立性,替换时发生写时拷贝。

关于xshell如何运行起来的

bash进程创建子进程,bash等待子进程,我们输入的指令替换子进程,bash正常运行不影响,子进程运行的是我们的输入的指令,然后得到结果(替换原来的子进程)

各种exe接口
第一个是最简单的,在上面已经展示了。接下来主要再学习4种:以带l、v、p、e的进行区分
在这里插入图片描述

  • e:与环境变量有关
  • p:不需要路径,只要给程序名字就行,系统替换的时候,会自动去环境变量种查找
  • l:列表的形式,主要是在参数列表中,有多个参数的
  • v:数组,参数直接传数组名就行了

在这里插入图片描述

一个程序调用其他不同语言的程序
修改makefile,创建一个c++文件,使用execl函数调用c++文件。无论什么语言,只要能在linux下运行,都可以去程序替换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

环境变量的传递:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们并没有传环境变量,但是子进程默认就拿到了,为什么?因为默认可以通过地址空间继承的方式,让所有的子进程拿到环境变量。进程程序替换,不会替换环境变量数据。

所以子进程拿到环境变量的方式有以下3种:
一、以继承的方式,直接全部拿到(上面的代码有展示)
二、新增环境变量——putenv。bash本地看不到,但是可以被子进程继承拿到,显示的时候就能看到了。
在这里插入图片描述
在这里插入图片描述
三、设置全新的环境变量——execle(覆盖)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

也可以把环境变量表以参数的形式传递过去
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单片机原理及技术(六)—— 中断系统的工作原理

目录 一、AT89S51中断技术概述 二、AT89S51中断系统结构 2.1 中断请求源 2.2 中断请求标志寄存器 2.2.1 TCON 寄存器 2.2.2 SCON 寄存器 三、中断允许与中断优先级的控制 3.1 中断允许寄存器 IE 3.2 中断优先级寄存器 IP 四、响应中断请求的条件 五、外部中断的触发…

深入理解java web分层架构的高内聚低耦合

​ 在软件开发中,构建一个高效、可维护且可扩展的应用系统一直是开发者追求的目标。分层架构和依赖注入(IOC)是实现这一目标的重要策略。本文将深入探讨三层架构的高内聚特性、低耦合的设计原则,以及如何通过IOC(控制反…

FPGA开发——在线调试工具Signal Tap的使用

一、简介 在我们进行FPGA进行开发时通常都会经历代码编写,仿真,下板验证等过程。使用FPGA进行开发的小伙伴都知道,在代码编写时往往花费不了太长的时间,下板验证更是。在开发中占绝大部分时间的是仿真,有时候编写代码只…

基于Python的火车票售票系统/基于django的火车购票系统

摘 要 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代&…

Ubuntu虚拟机服务器的搭建

01.VMware安装 略。 02.Ubuntu虚拟机安装 略。 03.配置Ubuntu虚拟机网络 参考视频: Ubutu虚拟机网络配置(桥接)https://www.bilibili.com/video/BV1bG411V72A/?spm_id_from333.999.0.0&vd_sourced1fd4bcc46805ab35cc8bbb5a8bf318f…

解决springboot中Aspect注解不生效问题

如下图所示,配置了一个注解类型的Aspect,结果一直不生效 运行结果可以看到,其他非注解类型的Aspect都顺利执行了,但是这个注解的切面就是没有执行 当时也在网上搜了半天,包括在启动类增加配置,接口都要加上…

HTTPS通讯全过程

HTTPS通讯全过程 不得不说,https比http通讯更加复杂惹。在第一次接触https代码的时候,不知道为什么要用用证书,公钥是什么?私钥是什么?他们作用是什么?非对称加密和对称加密是啥?天,…

深度学习设计模式之外观模式

文章目录 前言一、介绍二、特点三、详细分析1.核心组成2.代码示例3.优缺点优点缺点 4.使用场景 总结 前言 外观模式是结构型设计模式,定义一个高层接口,用来访问子系统中的众多接口,使系统更加容易使用。 一、介绍 外观设计模式&#xff08…

一文掌握 Web 测试:功能、界面、兼容与安全的综合测试指南!

随着Web技术的不断演进,测试除了对应用的功能性、界面美观性、跨平台兼容性的基本要求外、安全性和性能的要求也逐步增高。因此,全面、系统的测试思维和策略成为了保证Web应用高质量的关键因素。本篇文章将从功能测试、界面测试、兼容性测试和安全测试四…

transformer-explainer

安装和启动 找到这个项目,然后装好了。 这个项目的目的如名字。 https://github.com/poloclub/transformer-explainerTransformer Explained: Learn How LLM Transformer Models Work with Interactive Visualization - poloclub/transformer-explainerhttps:/…

BVS:多强联手,李飞飞也参与的超强仿真数据生成工具,再掀数据狂潮 | CVPR 2024

BEHAVIOR Vision Suite(BVS)是一个新型工具包,旨在系统评估和全面理解计算机视觉模型。研究人员能够在场景、对象和相机级别控制各种参数,有助于创建高度定制的数据集。 来源:晓飞的算法工程笔记 公众号 论文: BEHAVIO…

Java基础开发之编译异常和运行异常

一、getProperties()方法 1.System类提供一个getProperties()方法用来**当前系统的全部属性,它会返回一个Properties对象,也封装了系统的全部属性,这些属性的存在是以键值对的形式。 2.getProperties()方法使用例子: public cl…

springboot粮仓管理系统的设计与实现论文源码调试讲解

第3章 系统分析 本文作者在确定了研究的课题之后,从各大数字图书馆下载文献来阅读,并了解同类型的网站具备的大致功能,然后具体事务具体分析,得出本系统要研究的具体功能与性能。虽然分析系统这一阶段性工作主要是确定功能&#…

Java二十三种设计模式-状态模式(20/23)

本文深入探讨了状态模式,一种允许对象根据其内部状态变化而改变行为的软件设计模式。文章从定义、组成部分、实现方式、使用场景、优缺点分析、与其他模式的比较,到最佳实践和建议,全面介绍了状态模式的各个方面。通过Java语言的实现示例和实…

如何高效搜集知乎热门话题? 掌握这五种搜索技巧

本文将深入探讨如何高效地在知乎平台上挖掘热门话题,通过揭秘五大实用搜索技巧,帮助内容创作者、市场分析师快速捕捉网络热点,提升内容相关性和曝光率。掌握这些技巧,让你的文章或产品始终站在潮流前沿。 一、为何关注知乎热门话…

Ropdump:针对二进制可执行文件的安全检测工具

关于Ropdump Ropdump是一款针对二进制可执行文件的安全检测工具,该工具基于纯Python开发,是一个命令行工具,旨在帮助广大研究人员检测和分析二进制可执行文件中潜在的ROP小工具、缓冲区溢出漏洞和内存泄漏等安全问题。 功能介绍 1、识别二进…

Python实现水果忍者(开源)

一、整体介绍: 1.1 前言: 游戏代码基于Python制作经典游戏案例-水果忍者做出一些改动,优化并增加了一些功能。作为自己Python阶段学习的结束作品,文章最后有源码链接。 1.2 Python主要知识: (1&#xf…

网络安全-防火墙初步认识。

文章目录 1. 防火墙是什么?2. 防火墙的工作原理是什么?3. 防火墙的分类有哪些?4. 实战4.1 防火墙管理和实验介绍4.2 防火墙命令行初体验实验目标:实验步骤: 4.3 防火墙Web初体验实验目标:实验步骤&#xff…

canvas实现图片矩形截图,矩形旋转后的截图,旋转后的截图摆正显示

一、效果图 二、主要代码 获取矩形框中地方的截图数据 1、先获取矩形四点在画布上的实际坐标值; 2、计算矩形此时实际的宽和高,便于设置后期临时矩形的宽和高; 3、可能矩形旋转了一定的角度,我们新建一个临时的画布tempCanvas&am…

mkv怎么改成mp4?3种mkv转mp4格式方法的介绍

mkv怎么改成mp4?将MKV格式视频转换为MP4格式,能显著提升兼容性,让视频在更多设备、平台上流畅播放。无论是智能手机、平板电脑、智能电视还是网页浏览器,MP4格式都具备广泛的支持,从而扩大视频的传播范围和受众群体。这…