单进程版程序替换——最简单的程序替换
程序替换(Process Replacement)是Linux/Unix系统中一个重要的概念,指的是一个正在运行的进程完全被另一个程序替换的过程。这是通过exec
系列函数实现的。
特点:
1.进程不变性。替换前后进程的PID、优先级、文件描述符等内核数据结构保持不变,仅用户空间的代码和数据被覆盖
2.内存空间重构。新程序的代码和数据从磁盘加载到内存,替换原进程的用户空间内容。重新建立页表映射,修改虚拟地址与物理内存的对应关系。
3.不创建新的进程。与fork()
不同,exec
不会创建新进程
进程替换原理
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数 以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
回想之前的现象,为什么After,I am a process这个打印?这是因为发生程序替换后代码段和数据段发生了改变,execl以后的代码不再存在于代码段,而是被新替换进来的程序代码取代!只有exec函数替换失败,才会执行exec函数后的代码。并且exec函数只有失败返回值,没有成功返回值。
小知识:CPU如何知道新加载进来的程序的入口地址在哪?
Linux中形成的可执行程序是有固定格式的——ELF,可执行程序有程序表头,其可以将各个段(代码段、数据段等)加载到内存,同时该字段存储了程序的入口地址。
接口介绍
第一个参数是用来找到程序,后续的参数是告诉操作系统如何执行这个程序,主要是要不要涵盖选项,要涵盖哪些?
execlp中的p是指的PATH,execlp会在默认的PATH环境变量中寻找。后面参数同上
第一个参数是寻找程序的地址,第二个参数是一个字符串指针数组,替换了可变参数。argv会被传递给相应程序的main函数作为命令行参数。
p是指的PATH,vp会在默认的PATH环境变量中寻找。后面参数同上。
在单进程中,程序替换是将可执行程序的代码和数据加载到内存中,因此exec系列函数承担的是加载器的效果。
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量
多进程版进程替换
如何将父进程自己定义的命令行参数导给子进程?
我们调用execl或者execv将我们设置的命令行参数传递给替换进程。
我们打印一下替换进程的环境变量
函数execv没有传递环境变量!环境变量是什么时候给子进程的?
环境变量也是数据,创建子进程的时候环境变量就已经被子进程继承下去了!但程序替换后环境变量信息照样能打印,这是因为程序替换中环境变量不会被替换。
如果向给子进程传递不同于父进程的环境变量,该如何传递?
1.新增环境变量
第一种,直接在命令行添加新环境变量,这样在其上运行程序都属于其子进程,子进程继承父进程的环境变量,这样程序中间有了我们添加的新环境变量
第二种,不想在命令行添加新环境变量,而是在自己程序中添加并传递给子进程,在父进程中调用putenv()函数
我们在mycode.c中添加新环境变量,并被子进程成功继承,但是命令行却没有该环境变量。
2.彻底替换环境变量
当传递是我们自己定义的环境变量,会覆盖原有的环境变量。此处调用的是系统接口execve而不是库函数,如果想要调用execvpe和execle