Linux 进程3

进程地址空间

CPU读取数据都需要地址,在计算机中所有东西都是一种数据,包括我们的进程。

这是一个进程空间示意图,操作系统通过task_struct结构体链表来管理每一个进程,结构体里面有一个指针指向操作系统为进程开辟的一段空间,里面就是我们熟悉的栈,堆,静态区,代码段等程序的空间。

这个空间是一段连续的地址,但它不是真实的是一种映射通过页表映射到真实物理内存的一个方便的映射关系。所以其实在真实的物理内存中进程与其数据的存放不一定是连续的,只是通过了页表的映射方式来让进程的空间地址看起来是连续的而已,这个叫做虚拟内存空间。

这一段代码,定义了一个全局的变量val并在子进程中修改为100,子进程在linux中会发生写时拷贝即在修改的时候对其进行拷贝再修改所以我们在打印的时候看到父子进程的val值不同是正常的,但是这里的地址也是相同的。真实内存中一个地址对应一个字节,同一个地址有两个不同的值是不可能的,所以我们可以确定在程序内这个地址用的也是虚拟地址,而其相同是因为子进程将包括页表在内的信息都复制下来了,但是映射的物理内存空间是不同的。就是相同的页表相同的地址但是对应着不同的内存单元所以就发生两个不同的值。

fork函数

平时使用计算机我们可能同时看着视频,开着游戏,然后又在工作,那么这些都是一个程序,但是这些程序却能同时运行,这是一种CPU的并发或者并行处理多个事务的能力。其实不止上面的,就我们打开一个视频APP点开一个视频也是需要下载和播放这两个工作同时发生的,一个APP就可以看作是 一个程序那么这个两个同时发生的事件是不可能在一个进程里的,因为我们的代码都是从上到下依次执行语句的一定会有先后顺序,所以这里介绍一个系统调用函数fork就可以让我们做到一个程序同时执行两个事务。

fork函数是一个系统调用函数,在程序中可以为当前进程创建一个子程序,子程序是继承自当前程序的所有信息。所以上面进程地址空间中的虚拟地址都是相同的。

当我们调用了fork函数之后当前程序会被挂起,跳转到内核程序中(因为fork是一个系统调用函数),当轮到当前进程的时间片的时候,就会在内核中创建一个进程,在linux中就是创建一个进程PCB这个PCB基本上就是复制的父进程的,然后赋予子进程ID。一般创建一个进程系统会给分配一段进程地址空间但是这个是不分配的直接调用父进程的为了节省消耗提升效率,只有我们执行下去将里面的一些数据进行修改的时候系统才会进行数据的拷贝并分配一块新的地址空间给子进程(这是写时拷贝)。若是整个进程结束都没有对数据进行修改,那么这个拷贝就不会发生,父子进程会一直公用一段空间。

fork()的返回值类型为pid_t是一个宏其实就是一个int类型,若是返回的-1表示进程创建失败,若是为0表示当前进程为子进程,若是大于0表示当前进程是父进程。是否很奇怪,我们创建的进程到哪里去了呢,父进程又是怎么去管理呢?

当我们进入fork函数之后就不再在程序内部而是在内核程序中了,这时内核创建了一个进程PCB链接入进程队列中,这时候还没返回到调用fork的进程中但是已经是有两个进程在了,而且两个进程在同一行中返回接收fork的返回值,这时已经是两个并发或者并行运行的进程了,所以接下来的所有代码父子进程都会继续执行。而我们分辨父子进程的方式就是返回值,父进程会返回子进程的PID以方便对子进程进行管理,一般就是接收子进程的退出信息。若是父进程比子进程先结束那么子进程会由父进程的父进程即祖宗进程所继承,我们以命令行启动进程为例就是bash进程会继承子进程称为子进程新的父进程。若是子进程先于父进程结束会给父进程返回一个退出码,父进程读取退出码就能只能子进程是完成任务退出的还是出异常退出的,若是父进程一直没有接收那么子进程就会成为僵尸进程一直占用资源不会释放PCB和地址空间导致内存泄漏。

exit函数

exit用于终止一个进程的函数也是一个系统调用,_exit()是直接进入内核空间执行进程终止的命令。

exit()会先执行用户定义的清理函数,将对应的缓冲区冲刷在进入内核空间执行进程终止的命令。

与return不同的是return需要在主函数中调用才是进程终止,而exit函数则是无论在那里调用都是终止当前进程,用法与return相似。

wait函数

当我们创建了子进程之后一般都需要由父进程等待子进程退出了之后并接收子进程的退出码才退出。不然就会导致孤儿进程或是僵尸进程,孤儿进程还好会由其祖宗进程继承但是出现僵尸进程的话就会导致内存泄漏影响效率,甚至无法创建新进程。

wait函数就是给父进程用于等待子进程退出的函数。

pid_t wait(int* status) 函数的参数是个输出型参数,我们在外部定义一个int型变量将其地址传递过去,此函数会将退出的信息赋给这个地址中。返回值是一个pid,是退出的进程的pid。wait函数是阻塞等待的,当执行到这条语句时会一直阻塞等待一个进程结束。

pid_t waitpid(pid_t pid,int* status, int options),函数的第一个参数是等待的进程pid,若是输入-1的话就是等待任意一个进程与wait函数的效果一样,第二个与wait函数一样,

第三个参数是等待选项即等待的方法:

WNOHANG:如果没有子进程结束,则立即返回,不阻塞。

WUNTRACED:如果子进程进入停止状态,但不是由于接收到信号而停止,则立即返回其状态。

WCONTINUED:如果子进程继续(发送SIGCONT),则返回其状态。

这些参数是宏,若是我们在optins的位置输入0的话就会成为阻塞等待与wait函数一样。输入WNOHANG的话当执行到这条语句但是没有以结束但还没释放的进程就会立即返回0,并不会一直阻塞。输入WUNTRACED则是当有进程停止或者结束可能是接收到sigstop的信号或者等待资源等信号都会返回并返回此进程pid就不是只当进程结束才会返回。WCONTINUED 这个选项其实没什么用只是检测子进程是否被暂停后又被唤醒,若是的话调用WIFCONTINUED(status)会返回一个ture。

status参数

wait函数的参数是一个输出型参数,输出的信息如上图是一个位图形式的,整形的后十六位不使用只用前十六位,若是进程是正常结束的会有一个退出码退出码保存在第9到16位上,若是非正常退出则无退出码信息而是前8位保存终止信号的信息。core dump则是代表的core dump文件,若是进程是异常终止即由终止信号终止的系统可以保存进程的数据会创建一个core dump文件来存放一般都在当前目录下,若是此位为一则是创建了此文件,这叫核心转储。

exec进程程序替换

使用fork创建了一个子进程之后父子进程公用进程代码的,两个都是相同的那么如果我是需要执行一些其他的任务呢,若是将全部任务都放在一份代码中就会十分臃肿这份代码,所以我们需要使用进程程序替换让子进程换成另外一份代码去执行,这就是exec类函数的作用

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[]);

exec函数共有5个不过这五个都是调用的execve函数实现的,execve函数是真正的系统调用,这些都是对execve函数的封装。参数不同就意味这功能会有些许的差异。

l(list) : 表示参数采用列表

v(vector) : 参数用数组

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

e(env) : 表示自己维护环境变量

这里用execl举例,使用的是列表形式的,第一个参数是替换的进程的路径,第二个是进程名,后面的是选项,最后以NULL结尾。我们可以理解为在命令行中输入的命令,实际上我们的bash程序也是这么实现的。

 #include int main() 
{ char *const argv[] = {"ps", "-ef", NULL}; char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL}; execl("/bin/ps", "ps", "-ef", NULL);  execlp("ps", "ps", "-ef", NULL);  // 带p的,可以使用环境变量PATH,无需写全路径execle("ps", "ps", "-ef", NULL, envp); // 带e的,需要自己组装环境变量execv("/bin/ps", argv);   execvp("ps", argv); //带p的,可以使用环境变量PATH,无需写全路径execve("/bin/ps", argv, envp); exit(0); }// 带e的,需要自己组装环境变量 

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

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

相关文章

2-100 基于matlab的水果识别

基于matlab的水果识别。从面积特征、似圆形特征,颜色(rgb值和hsv值)特征对图像中的梨子、苹果、桃子、香蕉和菠萝进行特征提取,边缘检测识别,最后按照筛选出来的特征对水果进行识别。程序已调通,可直接运行。 下载源程序请点链接…

【CustomPainter】渐变圆环

说明 实现一个渐变圆环,起点位置为- π / 2。 效果 源码 GradientCircularPainter1 class GradientCircularPainter1 extends CustomPainter {final double progress;GradientCircularPainter1(this.progress);overridevoid paint(Canvas canvas, Size size) {c…

VCNet论文阅读笔记

VCNet论文阅读笔记 0、基本信息 信息细节英文题目VCNet and Functional Targeted Regularization For Learning Causal Effects of Continuous Treatments翻译VCNet和功能目标正则化用于学习连续处理的因果效应单位芝加哥大学年份2021论文链接[2103.07861] VCNet和功能定向正…

OpenCV特征检测(5)检测图像中的角点函数cornerMinEigenVal()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 计算用于角点检测的梯度矩阵的最小特征值。 该函数类似于 cornerEigenValsAndVecs,但它计算并存储协方差矩阵导数的最小特征值&…

2024上海工博会,正运动激光振镜运动控制器应用预览(二)

■展会名称: 第二十四届中国国际工业博览会(以下简称“上海工博会”) ■展会日期 2024年9月24日–28日 ■展馆地点 中国国家会展中心(上海) ■展位号 6.1H-E261 正运动激光加工控制解决方案主要分为激光振镜运动…

24 小时不关机的挂机云电脑,还能这么玩?

云电脑技术为我们提供了无限可能。特别是对于游戏爱好者,挂机云电脑不仅解决了传统电脑的局限性,还带来了更为便利的游戏体验。除此之外云电脑还有什么其他玩法呢? 01 挂机云电脑的优势 首先要知道,什么是挂机云电脑&#xff1f…

解锁自动化新境界:KeymouseGo,让键盘和鼠标动起来!

文章目录 解锁自动化新境界:KeymouseGo,让键盘和鼠标动起来!背景:为何选择KeymouseGo?KeymouseGo简介安装KeymouseGo简单函数使用应用场景常见问题与解决方案总结 解锁自动化新境界:KeymouseGo,…

操作系统 | 学习笔记 | | 王道 | 5.1 I/O管理概述

5.1 I/O管理概述 5.1.1 I/O设备 注:块设备可以寻址,但是字符设备是不可寻址的 I/O设备是将数据输入到计算机中,或者可以接收计算机输出数据的外部设备,属于计算机中的硬件部件; 设备的分类 按使用特性分类&#xff…

from tqdm.auto import tqdm用法详细介绍

tqdm 是一个 Python 库,用于在长时间运行的任务中显示进度条。tqdm.auto 是 tqdm 的一个版本,能够自动适配输出环境(如 Jupyter Notebook、命令行等),以确保进度条在各种环境下显示正确。下面是 tqdm.auto 的详细用法介…

英飞凌 PSoC6 评估板 RT-Thread 开发环境搭建

本文介绍如何搭建基于 RT-Thread Studio IDE 工具的 PSoC6 RTT 评估板的开发环境,通过搭建一个简单的工程,将代码编译、下载到 PSoC6 RTT 开发板。 安装软件包 首先需要安装 RT-Thread Studio,如果你还没安装,可以点击这里下载安…

MySQL 中的 UTF-8 与 UTF8MB4:差异解析

在 MySQL 数据库中,字符集的选择对于数据的存储和处理至关重要。其中,UTF-8 和 UTF8MB4 是两个常见的字符集选项。那么,它们之间到底有什么区别呢? 一、字符集简介 UTF-8 UTF-8(8-bit Unicode Transformation Format&…

中伟视界:AI边端云一体化管控平台的特色功能介绍及其工作原理

在当前的数字化浪潮中,人工智能(AI)与物联网(IoT)技术逐渐渗透到各行各业,而如何在复杂、多层次的技术环境中高效管理和控制这些系统,成为了企业追求自动化、智能化发展的关键挑战。为了满足这种…

docker-compose up 报错:KeyError: ‘ContainerConfig‘

使用命令查看所有容器: docker ps -a 找到有异常的容器删除 docker rm {容器id} 后续发现还是会出现这种情况,尝试使用更高版本的docker-compose后解决

Java开发-面试题-0035-Spring代理方式有哪些

Java开发-面试题-0035-Spring代理方式有哪些 更多内容欢迎关注我(持续更新中,欢迎Star✨) Github:CodeZeng1998/Java-Developer-Work-Note (技术)微信公众号:CodeZeng1998 (生活&…

【Python报错已解决】SyntaxError invalid syntax

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

怎么解除BitLocker对磁盘的加密?

BitLocker是一种Windows操作系统内置的加密功能,用于保护用户的数据安全。它通过对整个磁盘进行加密,防止数据被未经授权的用户访问。BitLocker主要用于保护笔记本电脑和台式机中的重要数据,尤其是在设备丢失或被盗的情况下。怎么解除BitLock…

【Redis入门到精通二】Redis核心数据类型(String,Hash)详解

目录 Redis数据类型 1.String类型 (1)常见命令 (2)内部编码 2.Hash类型 (1)常见命令 (2)内部编码 Redis数据类型 查阅Redis官方文档可知,Redis提供给用户的核心数据…

Redhat 7,8,9系(复刻系列) 一键部署Oracle19c rpm

Oracle19c前言 Oracle 19c 是甲骨文公司推出的一款企业级关系数据库管理系统,它带来了许多新的功能和改进,使得数据库管理更加高效、安全和可靠。以下是关于 Oracle 19c 的详细介绍: 主要新特性 多租户架构:支持多租户架构,允许多个独立的数据库实例在同一个物理服务器上…

鸿蒙开发之ArkUI 界面篇 十四 个人中心导航界面

鸿蒙要实现如图效果,代码简洁到令人难以置信: 整体布局是水平方向的,用row容器,左边是Image加载图标,中间是Text。右边也是Image加载图片,主轴子组件之间的距离用justifyContent(FlexAlign.SpaceBetween)&a…

MySQL 中的锁定粒度:理解与应用

在 MySQL 数据库的使用中,锁定粒度是一个至关重要的概念。它决定了数据库在并发控制中锁定的范围和程度,对数据库的性能和并发能力有着深远的影响。今天,我们就来深入了解一下 MySQL 中的锁定粒度是什么意思,并通过实际案例来更好…