1、概念说明
在后面的后面的章节中,“Linux—线程、进程与进程通讯(1)—进程的概念和创建”我们提到了怎样创建子进程(fork()、vfork())。
然而目前我们只能通过把所有代码写在一个文件的形式来进行调用。在实际开发过程中,假如用这些方法去写代码,都会造成资源浪费(相同内容重复写,占用空间)、不易维护(调整时linux模拟,每位代码都得改一遍)
这个时侯,我们就须要用到“进程程序替换”(即不同文件之间,调用代码)。
进程程序替换
进程程序替换:用新的程序代码和数据来取代原先进程的代码和数据,是取代进程。(不创建新进程,创建新进程用fork()、vfork())。其中新的程序代码和数据,可以是来自其他文件的。
2、exec族相关函数
//exec函数族:指的是一系列函数
#include//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[]);
其中,所有函数都是以“exec”开头,依据函数名前面的字符不同,具有不同的参数和返回值:
下边会重点介绍:execl()函数
函数说明
#include//exec函数族所需的头文件
int execl(const char *path, const char *arg, ... );
参数:
path
需执行程序的路径名称(须要写路径全名称)
arg
需执行程序所带的参数,其中第一个参数,必须为可执行文件名子(不带路径);同时最后一个参数必须为NULL。
返回值:
exec函数族的函数,执行成功后不会返回;执行失败后,会设置errno并返回-1,之后从原函数的调用点继续往下执行。
运行实例:
实例1:使用execl()函数调用“ps”命令(程序快照)
#include
#include//exec函数族所需头文件
int main(void){
printf("before execl -> psn");//替换前
if((execl("/bin/ps", "ps", "l", "f", NULL)) == -1){
printf("execl failedn");
perror("reason");
}
printf("after execl -> psn");//替换后
return 0;
}
程序思路:
1、使用printf()函数复印“beforeexecl->ps”。用以测量使用execl()函数,是否会替换execl()之前的内容。
2、使用execl()函数进行替换,将后续内容替换为:“/bin/ps”中的ps命令,参数为elf
“/bin/ps”:为需执行程序的路径全名称,ps命令所需的程序在“/bin/ps”中;
“ps”:为第一个参数,即可执行程序文件名子(我们想执行的是ps,所以输入ps)
“l”、“f”:为后续参数,类似于shell命令“ps-elf”中的e、l、f
“NULL”:为最后一个参数,必须为NULL
3、使用printf()函数复印“afterexecl->ps”。用以测量使用execl()函数,是否会替换execl()以后的内容。
运行结果:
1、“beforeexecl->ps”正常复印,即使用execl()函数,不会替换execl()之前的内容。
2、正常显示程序快照,其内容与shell命令中的“ps-elf”相同。
3、“afterexecl->ps”未复印,即使用execl()函数,会替换execl()以后的内容。
tips:看见第2点linux进程与线程通讯,你们可能会有疑惑:运行./test和ps-lf显示的明明不一样啊?
(你们可以思索一下,答案我会写在文章的最后。)
实例2:在text1.c文件中,调用text2.c文件的内容
让我们先编撰text2.c代码内容:
#include
#include//exec函数族所需头文件
int main(int argv, char *argc[]){
int i;
printf("This is test2 n");//表明这是test2.c文件
printf("argv = %dn", argv);//打印输入参数argv
if(argv != 0){
for(i = 0; i < argv; i++){//依次打印输入参数argc
printf("argc[%d] = &s", i, argc[i]);
}
}
printf("test2 endn");//表明test2函数结束
return 0;
}
程序思路:
1、利用printf()函数,复印“Thisistest2”;以后复印参数argv的值
2、利用for循环,依次复印argc的值(共有argv个值),即argc[0]—argc[argv-1]
3、打印“test2end”标识函数执行结束
运行结果:
在执行时输入:"./test2ilovetext"
可以看见:参数argv为4,并将字符串“./test2”,“i”,"love","text"分别输出
接出来,在同一目录下创建test1.c,让我们来写test1.c的内容
#include
#include
int main(int argv, char *argc[]){
printf("This is test1n");
if((execl("./test2", "test2", "i", "love", "text", NULL)) == -1){
perror("execl failed");
}
printf("test1 endn");
}
程序思路:
1、使用printf()函数,复印“Thisistest1”,表明正在运行test1
2、使用execl()函数,进行替换。即找寻“./test2”路径下linux虚拟机,执行test2,参数为“i","love","txt”
运行结果:
可以看出:
1、先复印“Thisistest1”,表示早已开始执行test1程序
2、然后复印“Thisistest2”,表示开始执行test2程序,即替换成功
3、分别复印argv的值4linux进程与线程通讯,以及参数“test2”,“i”,“love”,“text”
4、打印“test2end”表示test2结束,未复印“test1end”表示test1替换后,不会继续执行接出来的函数