单进程版的进程替换:
现象:
运行结果:
没有执行execl后面的代码;
基本原理:
其实就相当于我自己对应的程序在运行的时候,
这个可乘程序一旦用execl来加载起来,做法特别简单粗暴,它就拿着新程序的代码替换老程序的代码,新程序的数据替换老新程序的数据替换老程序的数据。
exec* 后续的代码执行替换失败会怎样?
才可能执行后续代码exec* 函数,只有失败返回值,没有成功返回值!!
换完之后呢,让我们对应的CPU执行当前新程序对应的入口地址,让我们直接执行新程序。
整个过程之中,我们只是把当前进程的代码和数据进行了替换,而并没有更改当前进程,尤其是没有创建新进程这就叫做程序替换。
多进程版的程序替换:
现象:folk后,由子进程来执行对应的这个程序替换的时候,我们的父进程看起来是没有受影响的。
可是在单进程版的时候,我们发现我们的进程直接就被替换掉了。
当我们在进行创建子进程的时候,子进程进行程序替换,那么并不会影响父进程。
这时因为我们有写实拷贝技术以及进程之间是要保留自己所对应的独立性。
所以我们程序替换并不影响父进程。
程序替换有没有创建新的进程?
不创建新进程,只进行进程的程序代码和数据的替换工作!
我们的CPU如何得知程序的入口地址?
Linux中形成的可执行程序,是有格式的,ELF, 可执行程序的表头,可执行程序的入口地址就在表中!!!
其实表中所有的除了代码和数据,其他属性信息也能拿到,
一方面初始化诸如地址空间,页表这样的结构。
一方面报告诉CPU代码从哪里入口。
所以当我们重新替换时,它就知道原来一旦替换成功之后,就从新程序开始,从零开始执行了。
替换函数:
其实有六种以exec开头的函数,统称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[]);
这些函数原型看起来很容易混,但只要掌握了规律就很好记。
第一个参数:决定如何找到该程序,以全路径或者相对路径的形式
后面的参数:如何执行这个程序,主要是要不要涵盖选项,涵盖哪些?
l(list) : 表示参数采用列表(命令行怎么写就怎么传)
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示环境变量...:可变参数,如果对应的函数它的参数个数是不定的,所以c、c++会给我们提供可变参数。
int execve(const char *path, char *const argv[], char *const envp[]);
只有execve是真正的系统调用,其它五个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在 man手册第3节。
这里的const的意思是:
指针不可被修改,而不是指针指向的内容不可被修改。
使用样例:
execl
在.cpp文件中
在.c文件中:
在makefile中:
运行即可用.c文件调用.cpp文件
execv
在.c文件中:
在.cpp文件中:
运行:
在默认情况下,即便是你没有给它传环境变量,这个环境变量的信息自动也会被我们的子进程拿到。
那么环境变量是什么时候给进程的呢?
环境变量也是数据,创建子进程的时候,环境变量就已经被子进程继承下去了!!!
所以,程序替换中,可以替换程序的代码和数据,但环境变量信息,不会被替换!!!
如果想给子进程传递环境变量,该怎么传递?
1新增环境变量:(父进程的地址空间中直接putenv!)
在.c文件中:
./运行之后:
2.彻底替换
如果传自己的环境变量呢?
在.c文件中:
make运行之后:
我们发现只有自己定义的环境变量。
所以在传递自定义的环境变量时,采取的策略时覆盖,而不是追加
shell脚本
以.sh结尾的这种就是我们对应的文件。
脚本语言上面所有的开头都以#!开头。
那么后面紧跟的是我们脚本语言的解释器(说一下脚本语言并不是脚本在跑,那么而是由解释器来解释式的执行的,脚本语言就是文本文件)
所谓的脚本语言呢?
其实就是这个bash就是命令行解释器。
从对应的这个文件里,一行一行地把内容拿出来拿出来之后,然后帮我们进行一行一行的去执行。
这就叫做命令行解释器以及对应的脚本语言
c语言把shell脚本调起来怎么调?
.c文件中: