进程替换可是个好东西,可以帮助我们模拟小shell~,
先看代码&&现象:
这就是程序替换,将原本的程序代替,然后去执行新的程序
所以我们发现我们原程序后半段的printf就没有打印了,因为后半段已经被替换掉了。
原理:
先输出一个结论:exec系列的函数并没有创建新的进程。
我们的进程 = 内核数据结构 + 代码和数据
本质exec*系列的函数就是类似linux下的一个加载函数,将磁盘上的文件加载到物理内存中。
将代码改为多进程:
可是如果我们还是想继续执行没被执行到的代码怎么办?
答案是使用fork(),创建子进程,让子进程被替换,父进程执行刚刚未被执行的代码。
记住不要忘记回收子进程哦,
由此可以看到fork创建出来的子进程有两个用途
- 执行部分父进程代码
- 执行一份全新的代码
我们exec就是后者。
我们的进程之间是具有独立性的,即具有独立的内核数据结构和代码与数据,数据会按需发生写时拷贝。
我们在以前的理解中代码是具有只读属性的,但是在OS眼中一视同仁,为了执行一份全新的程序,代码也会发生写时拷贝。
使用所有的替换方法,认识参数的含义:
我们再来回顾一下execl
函数
我们一直说exec是execute(执行的英文)的缩写,而后边的l代表
- l(list) : 表示参数采用列表
同理,我们后边如果跟v p e的字母的函数就是如下含义:
- v(vector) : 参数用数组
- p(path) : 有p自动搜索环境变量PATH
- e(env) : 表示自己维护环境变量
接下来我们来使用一下这些函数。
execv
execvp:
execlp:
execvpe:
重量级函数登场。
看到这个e我们肯定可以想到环境变量,而v我们已经知道这与命令行参数其实是一样的,
这是不是与我们main函数的参数有些过分巧合了呢?
没错,这些变量就是传递给我们将要执行新的程序的参数。
在这个函数使用讲解之前,我们先来考虑一下,我们exec系列函数可以替换我们自己的程序码?
答案是可以的,只要是进程我们几乎都可以替换(替换之前先考虑一下当前进程真的可以替换吗)。
那我们先写一个Cpp代码试验一下
运行结果:
这里我们也验证了一下进程没有改变的问题,替换后的进程pid
是不变的,证明没有创建新的进程。
同理,Python与脚本语言也可以被C语言替换,因为他们运行起来都是进程。
接下来我们可以看execvpe这个函数了,我们已经知道这里的argv与env参数是可以被新程序的main函数接受的。
那么我们来验证一下:
实验结果:
于是我们就知道execvpe可以自定义的传入环境变量。
- 可以采用全新的环境变量给子进程
- 可以用旧的环境变量给子进程
- 可以在旧的环境变量基础上改变一点给子进程。
我们看一下第三点如何实现:
extern + putenv即可实现。
系统调用:execve:
我们的所有exec系列C函数都是根据这个系统调用进行封装的。
为的是应对不同情况下的调用。