Linux操作系统~进程替换,exec系列函数的使用
创始人
2024-01-21 23:01:46

目录

1.概念/原理

(1).替换原理

(2).子进程调用execl执行程序替换,为什么父进程不受影响?

(3).exec*返回值

2.替换函数exec

execl

execv

execlp

execvp的(execv)

execve的参数(execle)

技:Makefile一次生成多个可执行文件

Q:为什么这里的clean要设置为伪目标?

exec系列函数总结


上一篇文章我们创建子进程的目的:  if else 让子进程执行父进程代码的一部分

如果我想让子进程执行一个“全新的程序”呢?? ————这就需要用到进程替换

1.概念/原理

        进程替换就是指进程不变(进程的pcb,进程地址空间不变),仅仅用替换当前进程的代码和数据的技术(新程序的替换旧进程的),叫做进程的程序替换,这样就好像子进程执行了一个全新的程序。

--有没有创建新的进程呢?   答案是没有

(1).替换原理

        用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

程序替换的本质是不是就是把程序的进程代码+数据(加载进特定进程的上下文中!!

C/C++程序要运行,必须的先加载到内存中!

如何加载呢?使用加载器

加载器的底层原理就是使用exec*程序替换函数


(2).子进程调用execl执行程序替换,为什么父进程不受影响?

父子代码难道不是共享的吗?为什么新程序替换了子进程的代码和数据以后,父进程不受影响呢?

        因为进程是具有独立性的,进程程序替换会更改代码区的代码,此时也会发生写时拷贝,拷贝一份代码和数据给子进程,然后再将新程序中的代码和数据替换子进程中的。


(3).exec*返回值

        只要进程的程序替换成功,就不会执行后续代码,意味着exec*函数,成功的时候,不需要返回值检测(exec系列函数执行成功以后,原进程中的代码和数据都会被替换掉,自然也就不会执行exec*后面的代码,exec*自然也就不会返回了;如果exec*返回了,那exec系列函数一定是执行失败了。)

只要exec*返回了,就一定是因为调用失败了!


2.替换函数exec

其实有六种以exec开头的函数,统称exec函数:

#include

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

int execve(const char *path, char *const argv[], char *const envp[]); 

函数解释:

  1. 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  2. 如果调用出错则返回-1
  3. 所以exec函数只有出错的返回值而没有成功的返回值。

命名理解

  1. l(list) : 表示参数采用列表(比如execl)
  2. v(vector) : 参数用数组
  3. p(path) : 有p自动搜索环境变量PATH
  4. e(env) : 表示自己维护环境变量(自己定义环境变量替代系统的环境变量)

execl

int execl(const char *path, const char *arg, ...);

  • l(list) : 表示参数采用列表(比如execl)

  • 第一个参数是path,填的就是你要执行的目标程序的全路径,即所在路径/文件名
  • 第二个参数之后,表示的是可变参数列表,要执行目标程序在命令行上具体该怎么执行,这里参数就需要一个个传递过去(“ls” “-a”  “-l”三个参数,缺一不可),最后必须传入NULL,作为参数传递的结束。
execl("/usr/bin/ls", "ls", "-l");

execv

int execv(const char *path, char *const argv[]);

  • v(vector) : 参数用数组

第一个参数和execl一样,path

第二个参数是一个指针数组,将execl中按照列表形式给出的参数放到这个数组里面。(最后需要加上NULL)

可以理解为它把这个参数数组,直接喂给了ls命令的main函数中的命令行参数数组argv

char* args[] = {"/usr/bin/ls","-al",NULL};
execvp("ls",args);

execlp

int execlp(const char *file, const char *arg, ...);

nt execl(const char *path, const char *arg, ...);

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

带了l所以是参数是以列表的形式给出

带了p所以第一个参数只需要给出文件名即可,在调用execlp的时候会帮我们根据环境变量PATH帮助我们找这个文件。

        要注意这两个ls的区别,第一个是指定程序/文件名,第二个ls是要在命令行上给出的参数(想要执行ls命令,ls本身也要给出)

execlp("ls", "ls", "-l");

execvp的(execv)

int execvp(const char *file, char *const argv[]);

  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH

第一个参数只需要给文件名

第二个参数给参数数组

char* args[] = {"ls","-al",NULL};
execvp("ls",args);

execve的参数(execle)

int execve(const char *path, char *const argv[], char *const envp[]); 

  • e(env) : 表示自己维护环境变量(自己定义环境变量替代系统的环境变量)

第一个参数给全路径

第二个参数给参数数组

第三个参数表示自己定义一个环境变量,然后传进来,替换系统的环境变量

自己有两个C程序,调用一个(test7)的时候运行另一个程序(to_exe)

test7:

#include
#include
#include
#include
using namespace std;int main()
{pid_t fork_id = fork();if(fork_id > 0)//父进程{cout << "this is father" << endl;wait(nullptr);}else//子进程{cout << "this is child" << endl;char* args[] = {"ls","-al",NULL};char* envp[] = {"666第一个参数","666第二个参数","666第三个参数",nullptr};execve("./to_exe",args,envp);}// bool a = nullptr;  //虽然报错但是对return 0;
}

to_exe:

        这样我们就可以在调用的另一个程序(to_exe)中使用自己定义的环境变量,打印出来,而不是系统的环境变量了。(如果直接运行to_exe,打印出来的是系统的环境变量)

#include 
#include 
#include 
#include 
using namespace std;
int main()
{cout << "to_exe is running" << endl;extern char **environ;  //获取当前的环境变量(一个字符串数组)for (int i = 0; environ[i]; i++){printf("%s\n", environ[i]);}printf("my exe running .... done\n");return 0;
}

 运行结果:

 


技:Makefile一次生成多个可执行文件

        Makefile默认只会生成第一个文件,所以我们可以声明一个目标all,然后将我们要生成的可执行文件作为all的依赖关系即可。

Q:为什么这里的clean要设置为伪目标?

        如果当前目录下存在文件名为clean的文件时,我们在shell中执行命令make clean时,由于这个规则没有依赖文件,所以目标被认为是最新的,从而不去执行规则所定义的命令,因此命令rm将不会被执行。为了解决这个问题,删除clean文件或者是在Makefile中将目标 clean 声明为伪目标。

[zebra@VM-8-12-centos test7]$ make clean
make: `clean' is up to date.

exec系列函数总结

        这六个函数(加上execvpe一共七个)实际上只是参数上的不同,最终都是调用execve,系统给我们提供的实际上只有这一个接口,其他接口都是在此基础上封装出来的。(通过man手册也可以发现execve在man手册的2区内,表示是系统调用)

all:test7 to_exe
test7:test7.ccg++ -o $@ $^ -std=c++11
to_exe:to_exe.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f test7

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
ps局部放大 放大某个部位的图... 软件类学习建议:边看边练习,可以先收藏后学习。一、使用Ctrl快捷键放大:Ctrl + +缩小:Ct...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
ps局部放大 放大某个部位的图... 软件类学习建议:边看边练习,可以先收藏后学习。一、使用Ctrl快捷键放大:Ctrl + +缩小:Ct...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...