目录
一、什么是进程程序替换
二、原理:
三、为什么要进行程序替换
四、六种替换函数
命名理解
(1)函数execl
(2)函数execv
(3)execlp
(4)execvp
(5)execle
(6)execve
一、什么是进程程序替换
所谓进程程序替换,顾名思义,就是使用一个新的程序替换原有的程序,进程将执行新程序的代码,而不再执行原有程序的代码,前面我们已经学习了如何创建一个进程,一般情况下,进程程序替换都不会使用父进程直接进行进程程序替换,而是让父进程调用fork()函数创建一个子进程,让子进程去执行一个新的程序即可。
二、原理:
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
从上图当中我们可以知道一个进程的出现必须先在PCB结构当中先构建自己的PCB块,有了对应的虚拟地址之后,然后虚拟地址通过页表映射的方式在物理地址当中找到位置,然后将磁盘当中的程序加载进入对应的物理地址。
三、为什么要进行程序替换
当一个父进程在创建子进程之后,父子进程的代码是共享的,子进程只能执行父进程的代码块,但是现在我们不仅要让子进程能够执行父进程的代码块,同时也要能够让子进程能够做一些父进程不能做的事情,也就是能够执行一个全新的代码(程序),这样就能实现父子进程做的事情有所差异,大大提高了办事效率,同时也使父子进程的代码彻底分离,维护进程的独立性。
目的:让子进程帮我们执行特定的任务。
四、六种替换函数
#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[]);
我们也可以在x-shell中通过 man 命令来查看。
如上的函数:
如果调用成功,则加载新的·程序,从启动代码开始执行,不在返回。
如果调用出错,返回-1
所以exec函数只有出错的返回值,而没有成功的返回值
-
命名理解
每一个函数看似十分复杂,其实,每一个不同的字母都各代表一个含义:
l (list) | 表示参数采用列表 |
v(vector) | 参数采用数组 |
p (path) | 有p自动搜索环境变量 |
e (env) | 表示自己维护环境变量 |
- 各函数之间的关系
事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve。
(1)函数execl
#include <unistd.h>
int execl(const char* path, const char* arg, ...);
返回值:失败返回-1
参数1:待替换程序的路径,比如“/usr/bin/ls”
参数2:待替换程序的名称,比如“ls”
后面的参数:待替换程序的选项,如
-a -l
等,最后一个参数为NULL
,表示选项传递结束
注意: 参数选项传递结束或不传递参数,都要在最后加上 NULL
,类似于字符串的 '\0'
案例:(这里替换调用的是 ls 命令)
1 #include<stdio.h>
2 #include<unistd.h>
3 int main(){
4 printf("程序替换:\n");
5 int ret=execl("/usr/bin/ls","ls",NULL);
6
7 //可以通过返回值查看是否返回成功
8 if(ret==-1)
9 {
10 printf("替换失败\n");
11 }
12
13 return 0;
14 }
运行结果:
(2)函数execv
"v"代表的是"vector" 即execv是以vector的方式传递参数的。
#include <unistd.h>
int execv(const char* path, char* const argv[]);
返回值:失败返回-1
参数1:待替换程序的路径,比如:"/usr/bin/ls"
参数2:待替换程序名及其命名构成--数组
注意:参数的最后仍需要加上NULL
#include<stdio.h>
#include<unistd.h>
int main(){
printf("程序替换:\n");
char* const argv[]={"ls","-a",NULL}; //以数组传入
int ret=execv("/usr/bin/ls",argv);
//可以通过返回值查看是否返回成功
if(ret==-1)
{
printf("替换失败\n");
}
return 0;
}
(3)execlp
#include <unistd.h>
int execlp(const char* file, const char* arg, ...);
返回值:失败返回-1
参数1:待替换程序名,比如“ls”,"pwd","clear"
参数2--N:可变参数列表,命令选项
该函数进行程序替换时,不需要写path路径,因为P代表有自动搜索的功能
#include<stdio.h>
#include<unistd.h>
int main(){
printf("程序替换:\n");
int ret=execlp("ls","ls","-l",NULL);
//可以通过返回值查看是否返回成功
if(ret==-1)
{
printf("替换失败\n");
}
return 0;
}
(4)execvp
#include <unistd.h>
int execvp(const char* file, char* const argv[]);
返回值:失败返回
-1
参数1:待替换程序名,需要位于
PATH
中参数2:待替换程序名及其命名构成的数组
注意:如果file的路径不在PATH中,则会替换错误
#include<stdio.h>
#include<unistd.h>
int main(){
printf("程序替换:\n");
char* const argv[]={"ls","-a","-l",NULL};
int ret=execvp("ls",argv);
//可以通过返回值查看是否返回成功
if(ret==-1)
{
printf("替换失败\n");
}
return 0;
}
(5)execle
#include <unistd.h>
int execl(const char* path, const char* arg, ..., char* const envp[]);
e表示env环境变量表,可以将自定义或当前程序·中的环境和变量传给替换程序
第一个参数:待替换程序的路径,比如:"/usr/bin/ls"
第二个参数:待替换程序名及其命名构成--数组
...
最后一个参数:替换成功后,待替换程序的环境变量表,可以自定义
(6)execve
execve 是系统真正提供的程序替换函数,其他替换函数都是在调用 execve
比如:
execl 相当于将链式信息转化为 argv 表,供 execve 参数2使用
execlp 相当于在 PATH 中找到目标路径信息后,传给 execve 参数1使用
execle 的 envp 最终也是传给 execve 中的参数3
#include <unistd.h>
int execve(const char* filename, char* const argv[], char* const envp[]);
返回值:替换失败返回
-1
参数1:待替换程序的路径
参数2:待替换程序名及其参数组成的argv表
参数3:传递给待替换程序的环境变量表