在介绍进程的程序替换时,我们首先得明白为什么要进行程序替换??程序替换是创建一个新的进程吗??替换了哪些东西??搞清楚这三点是至关重要的!!!
一、为什么要进行程序替换以及替换了哪些东西
调用用fork()函数创建子进程,子进程以父进程为模板,把父进程的PCB、地址空间、代码等都拷贝了一份,那子进程再去执行和父进程一模一样的程序又有什么意义呢?所以进行程序替换,将硬盘上的代码和数据替换到进程物理内存中的相应位置,让子进程去执行另外一个程序,以此来提高效率!
二、程序替换是不是创建一个新的进程
并不是的,程序替换只是子进程调用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[]);
系统调用:int execve(const char* path, char* const argv[], char* const envp[]);
函数区分:
- l(list):表示参数采用列表
- v(vector):表示参数采用数组
- p(path):有p自动搜索环境变量path
- e(env):自己维护环境变量
四、函数理解
- 这些函数如果调用成功直接加载新的程序,从启动代码开始执行,不再返回
- 如果调用出错则返回-1
- exec家族的函数,只有出错的返回值,没有成功的返回值
五、函数测试
- execl
文件名:test.c
int main()
{
int ret = execl("./hello", "./hello", NULL);
printf("%d \n", ret);
return 0;
}
输出结果:
可以看出,test可执行程序执行成功之后,并没有输出返回值ret,可见,exec类函数,调用之后,直接执行,成功后,不再返回。
当把代码改成如下:
int main()
{
int ret = execl("../hello", "./hello", NULL);
printf("%d \n", ret);
return 0;
}
输出结果:
可见执行失败,返回-1.
- execlp
无需给出路径,只需指明想执行谁(ls),你想怎么执行(“ls”, “-a”)
int main()
{
execlp("ls", "ls", "-a", NULL);
return 0;
}
输出结果:
- execle
int main()
{
char* const envp[] = {"PATH=/bin:/user/bin", NULL};
execle("/bin/ls", "ls", "-a", envp);
return 0;
}
输出结果:
- execv
int main()
{
char* const argv[] = {"ls", "-a", NULL};
execv("/bin/ls", argv);
return 0;
}
输出结果:
- execvp
int main()
{
char* const argv[] = {"ls", "-a", NULL};
execvp("ls", argv);
return 0;
}
输出结果:
- execve
int main()
{
char* const envp[] = {"PATH=/bin:/user/bin", NULL};
char* const argv[] = {"ls", "-a", NULL};
execve("/bin/ls", argv, envp);
return 0;
}
输出结果:
六、总结
上面的exec类函数,只有execve是真正的系统调用,其他5个函数最终都会调用execve,所以execve在man手册第2节,其他的在第3节。
下面是这六个函数的关系