【关于Linux中----进程控制和进程替换】

news2024/11/24 20:54:33

文章目录

  • 一、进程创建
  • 二、进程终止
    • 2.1进程退出场景
    • 2.2进程退出方法
  • 三、进程等待
    • 3.1进程等待必要性
    • 3.2进程等待的方法
    • 3.3获取子进程status
  • 四、进程程序替换
    • 4.1替换原理
    • 4.2替换函数
    • 4.3命名理解
  • 五、总结


一、进程创建

谈到创建进程,不得不提到一个函数----fork。

在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1

进程调用fork,当控制转移到内核中的fork代码后,内核做以下工作:

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

另外,在fork之前,父子进程做的事是相同的,fork之后,它们有了各自的分工,所做工作也不同。 具体的过程在之前的文章中已经写过了,这里不再赘述。

另外还需要铺垫一下写时拷贝的内容,这个在上一篇博客中讲到了,这里也不再说了。

fork常规用法:

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

fork调用失败的原因:

系统中有太多的进程
实际用户的进程数超过了限制


二、进程终止

2.1进程退出场景

我们接触到的所有进程,退出时的情况无非就只有三种:

代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止

思安考一个问题:为什么我们写的C/C++程序,在main函数最后都要return 0?

答:0表示进程的退出码,它代表的含义是进程运行并退出成功。

而非0的退出码则表示不成功,具体的数值对应具体的不成功的原因分类,这其中就包含了结果不正确和代码异常终止的情况。

举个例子:
在这里插入图片描述

在这里插入图片描述
这里我们让main函数的退出码为100。
执行结果如下:
在这里插入图片描述
补充:echo $? 可以获取最近一个进程的退出码,很明显第一个echo获取的是./myproc的退出码,而第二个echo获取的是上一次echo命令的退出码。

退出码存在的意义:

答:当进程退出失败时,可以根据退出码得知具体失败的原因。

下面来看一下不同的退出码代表的进程退出失败的不同原因:
在这里插入图片描述
在这里插入图片描述
这里暂时只贴出一部分信息,感兴趣的朋友可以自己探索一下更多的退出码信息。

2.2进程退出方法

①main函数return

这个方法毋庸置疑,大家都很熟悉。那么接下来提一个问题:
其他函数return可以使进程退出吗?

答:这个问题很简单,大家都知道,当然是不能。
做个实验:
在这里插入图片描述
在这里插入图片描述
可见,其他函数return并不会使进程退出。
实际上,main函数return是终止程序,而其他函数return是函数返回。

②exit终止进程
在这里插入图片描述

再举个例子:
在这里插入图片描述
在这里插入图片描述
可见,在return之前进程就已经退出了。

exit无论在main函数或是在其他函数中使用,都能使进程直接终止!

与exit相似的还有一个_exit:
在这里插入图片描述
看起来好像和exit没有什么不同,但它们既然是两个东西,就一定会有区别。
在解释它们的区别之前,先补充一个输出缓冲区的概念。

在程序输出数据时,会先把一部分数据放进缓冲区中,待缓冲区满了之后,再将它们刷新到显示器上。而如果要输出的数据不足以填满缓冲区,\n和return都可以让系统自动刷新缓冲区,从而让数据输出到显示器上。

而exit和_exit的区别就是,前者和return一样,可以刷新缓冲区,而后者则不作任何进程结束之后的收尾工作,直接将缓冲区的数据释放,并不会刷新到显示器上。

那么进程终止在OS层面都做了哪些改变呢?

答:与进程创建时进行的操作相反。进程终止时,OS会将进程的PCB,进程地址空间,进程的页表、映射关系和进程有关的代码和数据统统释放掉。

三、进程等待

3.1进程等待必要性

进程等待是什么?

答:父进程创建子进程的目的一般是为了让子进程帮助父进程完成一些任务,而父进程需要知道子进程完成任务之后的数据,而父进程等待子进程完成数据并退出的过程就是进程等待。

为什么要有进程等待(必要性)?

答:①父进程通过获取子进程退出的信息,可以得知子进程的执行结果。
②可以保证时序问题:子进程先退出,父进程后退出(不让子进程变成孤儿进程)。
③之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。所以父进程需要通过进程等待来释放子进程的资源。

3.2进程等待的方法

①wait

在这里插入图片描述

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL。

写一段程序体验一下:

在这里插入图片描述

按照理论来说,上面程序执行时,两个进程的变化过程应该是:子进程执行->子进程变成僵尸进程->父进程等待,此时子进程彻底消失->父进程执行完毕退出

接下来看一下结果跟理论是否相符:
在这里插入图片描述

可见,和理论答案完全一样!

②waitpid

在这里插入图片描述

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进
程的ID。

具体的代码只和上面的有一点点不同:
在这里插入图片描述
它们执行的结果是一样的,这里就不演示了。
另外再补充一点:waitpid中的第一个参数换为-1时,表示等待任意一个子进程,而在这个程序中,父进程只有一个子进程,所以将其换为-1的结果是一样的。

3.3获取子进程status

很明显,status是一个输出型参数,接下来我们直接把上面代码中的waitpid的第二个参数变为status,最后将其打印试一下:
在这里插入图片描述
在这里插入图片描述

这样的结果好像并不能看出什么,接下来将子进程的退出码改一下,再看一下结果:

在这里插入图片描述
在这里插入图片描述

所以不难发现:父进程拿到的status的值和子进程的退出码强相关。

再回到之前的问题,父进程等待的原因就是为了让父进程通过status的值拿到子进程的执行结果。

这里再讲一下status的构成

status是一个整数,具有32个比特位,而我们只是用低16位,高16位暂时不用管。

前面讲过,进程终止有三种情况。其实也可以分为两种----进程正常终止和异常终止。正常终止指的是通过return或exit结束进程,而异常终止指的是进程因为异常问题导致自己接收到了某种信号而被迫终止。所以status中就包含进程的退出状态和终止信号。

在这里插入图片描述
至于第八位涉及信号问题,这里不多解释。

经过解释,想要拿到一个进程的退出状态(退出是否成功,是否被异常终止)就很容易了(实质上就是分别拿到status的高八位和低七位)。
高八位:(status>>8)&0…0(24个0)1111 1111(也就是十六进制的0xFF)
低七位:status&0…0(25个0)1111111(也就是十六进制的0x7F)

代码如下(对上面的代码稍作改动):

在这里插入图片描述
执行结果如下:

在这里插入图片描述
结果正确。

但其实,拿到进程的退出状态,不用进行麻烦的位运算,直接调用系统规定的宏即可:

在这里插入图片描述
在这里插入图片描述
下面再解释一下waitpid的第三个参数option

上面的代码中,我们采用了waitpid的默认参数0,它代表的是父进程等待子进程时的状态为阻塞状态,所谓阻塞状态就是在此期间,父进程不被操作系统调度执行。

我们之前讲过进程PCB和运行队列的概念。
而阻塞等待实际就是在子进程运行,父进程等待期间,将父进程的PCB从运行队列移动到等待队列(进程状态从R变为S)。待子进程退出之后,父进程再重新回到运行队列。

与阻塞等待对应的就是非阻塞等待,在非阻塞等待期间,父进程会不断地监视子进程是否运行完毕,与此同时也可以做一些其他的事情,这就叫做父进程的轮询方案,对应的参数为WNOHANG:

在这里插入图片描述
在这里插入图片描述


四、进程程序替换

4.1替换原理

先提一个问题,之前我们创建的子进程,都是通过if else语句让其执行与父进程不同的事情,那么如果我们想让子进程执行一个新的程序呢?

答:通过进程替换,将原来进程中的代码和数据替换为需要被执行的程序的代码和数据。这种不改变进程,只改变代码和数据的技术就叫做进程替换。

在这里插入图片描述
在此过程中,系统没有创建任何新的进程!!!

4.2替换函数

要理解进程是怎么完成替换的,就必须要了解以下函数:
在这里插入图片描述
直接来一小段代码:
在这里插入图片描述

在这里插入图片描述
可以看到,execl之前的命令照样执行,但execl之后的命令便不再执行。原因就在于,在execl时进行了程序替换。
程序替换的本质就是将进程的代码和数据加载到指令的进程的上下文中,而加载这个操作就是靠加载器(exec系列的函数)来完成的。

另外,因为进程可以写时拷贝使得父子进程之间具有独立性。所以,如果父子进程中的任意一个进行了程序替换,都不影响另一个进程的执行结果。这里就不做演示了。

再补充一点,因为只要exec系列的函数执行成功,就不会执行原进程后面的指令,也就不会返回值。换句换说,只要exec系列的函数有返回值,就证明程序替换一定失败了!如下:

在这里插入图片描述
下面来详细解释execl的三个参数:

int execl(const char *path, const char *arg, …);
第一个参数path:替换原进程额进程的路径(所在目录/文件名缺一不可)
第二个参数 char * arg:你期望该进程在命令行上所执行的命令对应的字符串格式
第三个参数…:可变参数列表,需以NULL结尾,当命令行对应字符串写入完毕后用NUL收尾
具体样例可参考上面的代码。

4.3命名理解

其实exce系列的函数有六个:

#include <unistd.h>`
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg, …,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);

execl我们已经解释过了,下面讲解一下这些函数的命名规则
l(list) : 表示参数采用列表(execl)

像上面的例子中,将命令行对应的字符串一个个的列举出来的方法就是l(list)的方法。

v(vector) : 参数用数组(execv)

其实这个函数和上面的没什么区别,只不过是将execl中逐一列举出来的字符串统一存入一个数组中,再把这个数组当做函数的参数而已,代码如下:
在这里插入图片描述
在这里插入图片描述

p(path) : 有p自动搜索环境变量PATH(execlp)

其实这个跟execl差别也不大,但是它比execl更方便,方便的地方在于,execlp的第一个参数不用指定绝对路径,只需给出文件名,它会自动帮我们在环境变量中寻找该文件,如下:
在这里插入图片描述
执行结果相同,这里就不粘贴了。
e(env) : 表示自己维护环境变量

它的意思是可以不使用默认的操作系统提供的环境变量,而是可以自己提供或维护一个指定的环境变量。在这之前,先验证一个结论:程序替换不仅可以替换操作系统中的程序,也可以替换自己指定的(自己创建的)程序。为此,新建一个文件:

在这里插入图片描述

与此同时,把Makefile内容稍作调整:
在这里插入图片描述

而我现在想要让myproc进程执行myload,只需执行下面这段代码:
在这里插入图片描述

执行结果如下:

在这里插入图片描述

现在有了足够的铺垫,再来看如何进行execle操作:
首先在myproc.c程序中增加一个环境变量,并把它导入myload.c:
在这里插入图片描述

接下来在myload程序中将导入的环境变量打印出来:
在这里插入图片描述

执行结果如下:
在这里插入图片描述
至于其他的’p’,‘l’,'v’相组合的函数,实质上也就是将不同的功能融合在一起了,这里不一一演示了。
那么同样是程序替换,为什么要实现这么多接口呢?

答:实际上,真正的操作系统调用的程序替换接口只有一个----execve。
而其他的接口都是为了满足用户不同的应用场景,封装出来的,可以分别看一下手册中关于这几个接口的描述:
在这里插入图片描述
可以看到,execve不同于我们上面的其他接口,这个是手册2,而另外几个是手册3.区别在于手册3是由云服务器提供的,而手册2是由操作系统提供的。

五、总结

至此,关于Linux中的进程中非信号部分的内容就更新完了。在前面的几篇文章中,对于一些过程,我有意识地把一些进行详解,但还有一些只是一笔带过。因为我们都清楚,在学习操作系统的过程中,有时候不能太刨根问底。因为这本来就是计算机专业最难的一门学科,没有之一,就连操作系统的代码都是全世界的大佬一起维护的。可见,我们学习操作系统的路一眼望不到尽头啊。
另外,如果大家想针对之前的内容进行一次复习。推荐大家自己动手尝试写一个迷你版的shell并运行一下。因为此前已经有很多博主都写过这个了,我就不写了,感兴趣的朋友可以去搜一下其他博主写的代码,学习一下。
最后,关于Linux的内容还远远没有更完,不过我会持续更新的,希望大家可以一起进步!!!

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

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

相关文章

【Python】一个矩阵根据某一列选择大于或小于范围的数据

data_all data_all[data_all[:,3]>54201]data_all data_all[data_all[:, 3] < 54220] 上面就是根据数据的第3列&#xff0c;选取54201到54220的范围的数据&#xff1a;

单片机最小系统

单片机最小系统,或者称为最小应用系统,是指用最少的元件组成的单片机可以工作的系统. 对51系列单片机来说,最小系统一般应该包括:单片机、晶振电路、复位电路. 下面给出一个51单片机的最小系统电路图. 晶振电路&#xff1a; 单片机里都有晶振&#xff0c;在单片机系统里晶振作用…

2013年第四届C/C++ A组蓝桥杯省赛真题+解析+代码

目录 第一题&#xff1a;高斯日记 题目描述 思路分析 AC代码 第二题&#xff1a;排它平方数 题目描述 思路分析 AC代码 第三题&#xff1a;振兴中华 题目描述 思路分析 AC代码 第四题&#xff1a;颠倒的价牌 题目描述 思路分析 AC代码 第五题&#xff1a;前缀…

jsp就业管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 就业管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开 发&#xff0c;数据库为Mysql&#xff0c;使用ja…

蓝桥杯备赛(三)

目录 前言&#xff1a; 一、门牌制作 解析&#xff1a; 代码实现 二、寻找2020 解析&#xff1a; 代码实现 三、蛇形填数 解析&#xff1a; 代码实现 四、成绩分析 解析&#xff1a; 代码实现 五、单词分析 解析&#xff1a; 代码实现 小结&#xff1a; 前言&am…

热门Java开发工具IDEA入门指南——了解并学习IDE

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。 本…

面试了1个月连续失败4次,自动化测试真没想象的那么简单

我干测试6年了&#xff0c;最近面试又碰壁了… 这大概是我这一个月来第4次面试失败了&#xff0c;起初我投简历比较勇猛&#xff0c;奔着薪资高的有点儿名气的企业就开始海投&#xff0c;碰上了2家还不错的邀约面试&#xff0c;前面交流还行&#xff0c;一问到自动化测试就傻眼…

怎么进行视频恢复?推荐使用这4种方法

电脑视频怎么恢复&#xff1f;很多朋友在使用电脑的过程中&#xff0c;如果系统或者是存储文件出现问题的话&#xff0c;可能会出现视频丢失的情况。因为在使用电脑运行视频软件时&#xff0c;系统或者存储文件存在一些质量问题从而导致视频丢失。那么想要进行视频恢复&#xf…

【Leetcode】拿捏链表(一)——206.反转链表、203.移除链表元素

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《Leetcode》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 206.反转链表 203.移除链表元素 206.反转链表 力扣https://leetcode…

“工程化”对于大型数据平台而言,意味着什么?StartDT Hackathon来了

日前&#xff0c;2022 第三季 StartDT Hackathon 正式落下帷幕&#xff0c;以“产品工程化与可扩展性提升”为主题&#xff0c;主攻数据云这个“庞然大物”的工程化难题。 本届黑客松共吸引到 9 组参赛&#xff0c;均在 72 小时内完成项目并提测通过。有“单排孤勇者”&#x…

.NET JIT

定义 即时编译器 (JIT) 是 .NET 中公共语言运行时 (CLR) 的一部分&#xff0c;它负责管理 .NET 程序的执行&#xff0c;而与任何 .NET 编程语言无关。 工作流 特定于语言的编译器将源代码转换为中间语言。 然后&#xff0c;这种中间语言由即时 (JIT) 编译器转换为机器代码。 …

一篇文章学会React

React基础 文章目录React基础React介绍React特点React基本使用安装使用React脚手架&#xff08;***&#xff09;生成的项目的目录结构src下的index.js入口文件介绍脚手架中使用ReactJSX什么是JSX产生原因介绍JSX概述JSX语法注意事项JSX语法原理JSX学习声明式渲染条件渲染循环渲…

YOLOX改进

这是yolox的第2季了 如何设计在 mAP 和延迟方面表现良好的单级轻量级检测器&#xff1f;新型的单阶段轻量检测器和各种操作的准确性和延迟。此基础上分别提出了GPU和CPU的最佳操作和架构。一份YOLOX改进的实验报告&#xff1a;如何设计性能优异的单阶段轻量级目标检测器 论文…

Android Studio App自定义控件中视图的构造和测量方法讲解及实战(附源码 实现下拉刷新功能 超详细必看)

需要全部源码或者图片集请点赞关注收藏后评论区留言~~~ 一、视图的构造方法 Android自带的控件往往外观欠佳&#xff0c;开发者常常需要修改某些属性&#xff0c;比如按钮控件Button就有好几个问题&#xff0c;其一字号太小&#xff0c;其二文字颜色太浅&#xff0c;其三字母默…

表白爱心代码

文章目录一、演示&#xff08;python版&#xff09;代码二、演示&#xff08;html版&#xff09;代码一、演示&#xff08;python版&#xff09; 代码 # 在等一句我愿意 import random from math import sin, cos, pi, log from tkinter import *CANVAS_WIDTH 640 # 画布的宽…

hive最近的学习汇总-20221110

下个项目可能要用hive比较多 之前对分区、分桶搞不明白 趁着最近又学习了一下 ps&#xff1a;之前说的prophet在年底前一定会放上来的 hive是基于Hadoop构建的一套数据仓库分析系统&#xff0c;它提供了丰富的SQL查询方式来分析存储在Hadoop分布式文件系统中的数据&#xff1…

MySQL管理常用工具介绍

1.mysql 该mysql不是指mysql服务&#xff0c;而是指mysql的客户端工具。 -e选项可以在Mysql客户端执行SQL语句&#xff0c;而不用连接到MySQL数据库再执行&#xff0c;对于一些批处理脚本&#xff0c; 这种方式尤其方便。 示例&#xff1a; 2、 mysqladmin mysqladmin 是一个…

大三Web课程设计——悬崖上的波妞(4页) HTML+CSS(可以很好的应付老师的作业)

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

Java基础系列(八)——线程池详解

目录 线程池详解 什么是线程池&#xff1f;为什么要用线程池&#xff1f; 如何创建线程池 ThreadPoolExecutor类分析 ThreadPoolExecutor 饱和策略 简单的线程池Demo ThreadPoolExecutor线程池新增线程流程 线程池详解 什么是线程池&#xff1f;为什么要用线程池&#…

Word2Vec原理以及实战详解

文章目录前言0、序言(词嵌入介绍)一、Word2vec详解。二、CBOW 和 Skip-Gram详解。2-1、CBOW模型:&#xff08;已知周围词预测中心词&#xff09;2-2、Skip-Gram模型&#xff08;已知中心词预测周围词&#xff09;2-3、词嵌入的缺点三、Word2vec实战&#xff08;使用Gensim包&am…