【Linux】进程程序替换——exec函数簇

进程程序替换


为什么进程替换:

子进程被创建出来,运行和父进程一样的代码,但是往往我们把子进程创建出来并不是想让子进程去和父进程执行相同的代码,而是想让子进程去执行另外一个程序;最常见例子就是我们使用的Linux下的命令语言解释器Bash了;

我们在Bash下时输入的命令,Bash收到后会常见子进程去执行我们输入的命令然后将结果输出;因为Bash也是一个程序,如果Bash直接自己去执行输入的命令那么结束后退出,不是直接就关闭了难道一条命令要启动异常这是不合常理也是不对滴,所以Bash就要创建子进程去完成命令,而自身就一直等待命令处理就行了;而子进程就要进行程序替换去执行用户输入的命令了;

进程替换原理:子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
在这里插入图片描述
注意:这里的替换原理就是将子进程中映射页表中映射数据段和代码段的的位置进行初始化,然后让页表重新映射到要替换的程序的代码段和数据段;更通俗易懂的就是在页表上动手脚,修改页表映射让其映射到新的程序;而不是在页表映射的那一块物理内存上动手脚;

exec函数簇
#include <unistd.h>
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[]);
注意:以上的六个函数都可以完成函数替换,根据场景不同使用合适的函数;
所以前五个可以在手册man 3中找到,而最后可以在手册man 2中找到;
这六个函数中只有execve()函数时系统调用,其他都是在execve()函数上根据不同的场景不同封装而成;

在这里插入图片描述

函数解释

  • 如果函数调用成功则函数就会去执行没有返回值
  • 如果函数调用失败,返回-1
  • 函数只有失败时才返回,成功了就没有返回值

命名理解

  • l(list) : 表示参数采用列表,必须以NULL结尾
  • v(vector) : 参数用数组,必须以NULL结尾
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量,表示想给新的程序传入一些新的环境变量

在这里插入图片描述

//这个demo体会exec函数簇进行函数替换原理
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
 //基础函数exec,根据后面添加的不同函数的参数也是不相同的
 // execl("/usr/bin/ls","ls","-ll",NULL); //l代表:参数采用列表的方式,参数类表最后一定要以NULL结尾
 //execlp("ls","ls",NULL);//p代表:参数采用数组的方式,同样数组最后一定要以NULL结尾
 
 char* argv[]={"ls","-l",NULL};
 //execv("/usr/bin/ls",argv);
 //execvp("ls",argv);

 char *const envp[] ={"PATH=/bin:/usr/bin", NULL};
 //execle(/usr/bin/ls","ls","-ll",NULL,)
 execve("/usr/bin/ls",argv,envp);
  return 0;

注意:一般在调用exec函数后,直接就有exit()进行验证;
如果执行后获取到子进程的退出码是自己写的exit(函数内面的退出状态码),
那就说明替换就失败了(上述代码未注明);
}

在这里插入图片描述

总结

1、问什么exec函数簇没有返回值?

因为exec函数进行函数替换,替换的就是数据段和代码段,exec本身是有返回值的,但是这个返回值存在替换前的数据段,如果替换成功那么数据段已经被替换为新的数据段原先的的数据段已经被丢弃,那么exec的返回值也就被丢弃了所以就造成了替换成功没有返回值的现象了;但是相反替换失败了返回值存在替换前的数据段,而失败了该数据段没有被替换所以就会将返回值返回了;其实我们没有必要去关注这个返回值是什么,因为成功了没有返回值,相反失败了一个失败了那么就更没有必要去关注这个返回值是什么了;

2、在命令行输入的命令其实就是一个个进程,那么bash怎么样将这些程序跑起来?

bash先读取命令行输入的参数,进行命令解析。然后fork()创建一个子进程,bash开始wait()等待子进程;子进程开始进程替换然后将命令参数传入,去执行;

3、全局变量具有全局性,那么子进程怎样继承父进程的全局变量呢?

所有的程序都是从main函数开始的,而main函数有几个参数argc、argv、env等:其实就是在子进程函数替换时bash通过main函数的参数把环境变量给了要执行的进程

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值