【进程控制⑥】:进程替换/exec*()系列接口

【进程控制⑥】:进程替换/ exec*()系列接口

一.进程替换原理

我们的程序是可以将系统调用接口给封装起来,调用我们的程序本质就是调用了系统接口。

那么如何进行封装呢?通过exec*系列函数可以完成进程的程序替换,比如下面的是是比较标准的写法:

第一个参数是程序的路径,第二个参数就是程序名,而后面的参数就是可选择参数。

就比如这句代码将要把该进程替换成

/user/bin/ls路径下的程序名为ls的进程,并带上-a,-l选项。

然后当我们调用我们的程序时,就会调用到ls -a -l命令。

替换的原理是什么呢?

要知道可执行程序和文件都存储在磁盘中,而我们的程序的代码和数据则已经加载到内存中了。execl的方法非常暴力,直接替换。什么意思呢?就是直接将磁盘里的可执行程序(要替换的程序)的代码和数据替换现在进程的的代码和数据。替换完后,进程并没有被影响,该调用就调用,只不过物理内存里的地址发生改变了。虚拟地址并没有改变。

二.替换特点

替换的原理非常简单粗暴,那这样会不会出现问题呢?

上面的情况是单进程,如果是多进程如何进行程序替换呢?

多进程通常是让子进程进行程序替换,而父进程则等待子进程。

1.独立性

子进程在进行程序替换时,会不会影响父进程呢?为什么这样说呢?因为父子进程共用同一块代码和数据,当子进程被替换成新的可执行程序时,它的代码和数据也就被替换了,那父进程的代码和数据呢?

答案:当然不会!因为进程之间是具有独立性的---->[写时拷贝]

在子进程没有执行程序替换之前,与父进程共享代码和数据,当子进程执行程序替换时,需要将新的程序的代码和数据覆盖父进程的代码和数据,但不要慌!为什么呢?因为存在写时拷贝!

当往父进程的数据里写入时,就会发生写时拷贝,重新申请一块内存给子进程写入,所以父进程的数据并没有被覆盖掉。那代码呢?

代码有没有被覆盖掉呢?其实代码也存在写时拷贝,也没有被覆盖掉。

2.唯一性

程序替换有没有创建新的进程呢?

答案:并没有创建新的进程!只是进行进程的代码和数据的替换工作,并不会创建进程。原来的进程还是原来的PCB和进程地址空间和页表。只不过物理内存发生改变了,只需要改变一下页表的映射关系。

3.不变性

当子进程发生程序替换后,将会发现子进程的环境变量还是原来的环境变量,并没有被覆盖掉。我们知道子进程的环境变量是继承父进程的,那环境变量是什么给进程的呢?因为环境变量也是数据,创建子进程的时候,环境变量就已经被子进程继承下去了,当发生替换后,子进程的环境变量不变,说明程序替换是不会将环境变量替换的。

如果我们非要替换环境变量有没有方法呢?

当然有

①因为子进程是继承父进程的,所以我们只要修改父进程的环境变量就可以更新子进程的环境变量。

②或者使用带有e的exec*系列函数接口,这个是要自己传递环境变量,并且会覆盖原来的环境变量

4.不返回

还有就是进程程序替换成功后,就不会再返回,也就是exec*函数后面的代码就不会执行了,如果程序替换失败才会返回,后面的代码才会执行,所以这个就可以作为程序替换是否成功的判断条件,当替换失败了,就会执行子进程后面的代码,后面的代码肯定会有退出exit(),我们只要设置对应的退出码即可判断。

三.程序替换应用

程序替换的系统调用接口大概有7个,这里介绍经常使用的6个系统调用函数。

【exec*系列系统调用】

注意以上函数基本上第一个参数都是程序的路径,为什么要程序的路径呢?你要替换这个程序,也就是要执行这个程序,你执行这个程序不应该要先知道这个程序在哪吗?所以程序的路径是必须要有的。当找到这个程序之后呢?我们是不是就要思考,怎样执行这个程序呢?是以什么方式执行呢?而后面的参数就是用来传不同的参数使程序以想要的方式执行。[即命令行参数]

①execl:

--->'l' 注意这个l是什么意思呢?我们可以看成list链表,为什么呢?因为它后面的参数可以像链表一样,一个一个链接起来,不是一个整体。而如何使用呢?命令行怎么写的,你就怎么传就可以了。

②execlp:

'p',注意这个p是什么意思呢?这个p可以理解为环境变量中的PATH。默认路径,你注意到没它的第一个参数不是路径而是程序文件名,这说明像这样的函数我们不需要传路径,系统会到默认路径PATH里去找,只需要写要执行的文件名即可。

③execv:

'v',注意这个v是什么意思呢?这个v可以理解为vector数组,为什么这样说呢?因为它的后面的参数可以放进一个数组统一传过来。而不像list那样一个接着一个。

要注意理解:当我们调用exec*系列系统调用接口时,我们传的命令行参数,会被系统自动传给要替换的程序的main函数。要替换的程序的main会接收这些命令行参数的。

④execle:

'e',注意这个e是什么意思呢?这个e其实是环境变量env。我们进行程序替换时,也可以传递环境变量给要替换的程序。

exec*接口不仅可以替换那些已经存在的可执行程序,还可以调用我们自己写的可执行程序,就比如用C去调用C++程序。为什么可以呢?因为一旦程序执行就会变成进程,而进程就可以被替换,就算是其他语言写的程序一旦变成进程也可以被替换调用。

我们可以用自己写的程序来替换子进程,这样就可以验证当一个程序被替换时,系统会自动将那些环境变量命令行参数都传给替换的程序的main函数。

相关推荐
九河云1 分钟前
如何选择适合的AWS EC2实例类型
服务器·云计算·aws
AI街潜水的八角9 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
JSU_曾是此间年少38 分钟前
数据结构——线性表与链表
数据结构·c++·算法
€☞扫地僧☜€1 小时前
docker 拉取MySQL8.0镜像以及安装
运维·数据库·docker·容器
hjjdebug1 小时前
linux 下 signal() 函数的用法,信号类型在哪里定义的?
linux·signal
其乐无涯1 小时前
服务器技术(一)--Linux基础入门
linux·运维·服务器
Diamond技术流1 小时前
从0开始学习Linux——网络配置
linux·运维·网络·学习·安全·centos
写bug的小屁孩1 小时前
前后端交互接口(三)
运维·服务器·数据库·windows·用户界面·qt6.3
斑布斑布1 小时前
【linux学习2】linux基本命令行操作总结
linux·运维·服务器·学习
紅色彼岸花1 小时前
第六章:DNS域名解析服务器
运维·服务器