四、进程程序替换
1.替换原理
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
从上图可以看出,进程程序替换前后,进程本身并没有发生任何变化,只是所执行的代码发什么改变。
如果子进程进行程序替换,会影响父进程的代码和数据吗?
不会,首先进程是具有独立性的,虽然子进程共享父进程的代码和数据,但是由于进行了函数替换,发生了代码和数据的修改,此时就会进行写时拷贝。所有子进程进行程序替换时,并不会影响父进程的代码和数据。
2.替换函数
其实有六种以exec开头的函数,统称exec函数: 他们所需的头文件均为#include <unistd.h>
1.execl函数
int execl(const char *path, const char *arg, ...); // path --- 可执行程序的路径 // arg --- 可变参数列表,表示你要如何执行这个程序,并以NULL结尾 // 例如: execl("/usr/bin/ls", "ls", "-a", "-l", NULL);
2.execlp函数
int execlp(const char *file, const char *arg, ...); // file --- 可执行程序的名字 // arg --- 可变参数列表,表示你要如何执行这个程序,并以NULL结尾 // 例如: execlp("ls", "ls", "-a", "-l", NULL);
3.execle函数
int execle(const char *path, const char *arg, ..., char * const envp[]); // path --- 可执行程序的路径 // arg --- 可变参数列表,表示你要如何执行这个程序,并以NULL结尾 // envp --- 自己维护的环境变量 // 例如: char* envp[] = { "Myval=12345", NULL }; execle("./myexe", "myexe", NULL, Myval);
4.execv函数
int execv(const char *path, char *const argv[]); // path --- 你要执行程序的路径 // argv --- 指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾 // 例如: char* argv[] = { "ls", "-a", "-l", NULL }; execv("/usr/bin/ls", argv);
5.execvp函数
int execvp(const char *file, char *const argv[]); // file --- 你要执行程序的名字 // argv --- 指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾 // 例如: char* argv[] = { "ls", "-a", "-l", NULL }; execvp("ls", argv);
6.execve函数
int execvpe(const char *file, char *const argv[], char *const envp[]); // file --- 你要执行程序的路径 // argv --- 指针数组,数组当中的内容表示你要如何执行这个程序,数组以NULL结尾 // envp --- 自己维护的环境变量 //例如: char* argv[] = { "mycmd", NULL }; char* envp[] = { "Myval=12345", NULL }; execve("./myexe", argv, envp);
3.函数解释
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1
所以exec函数只有出错的返回值而没有成功的返回值。也就是说,exec系列函数只要返回了,就意味着调用失败
4.命名理解
这些函数原型看起来很容易混,但只要掌握了规律就很好记。
- l(list) : 表示参数采用列表
- v(vector) : 参数用数组
- p(path) : 有p自动搜索环境变量PATH
- e(env) : 表示自己维护环境变量
事实上,只有execve才是真正的系统调用,其它五个函数最终都是调用的execve,所以execve在man手册的第2节,而其它五个函数在man手册的第3节,也就是说其他五个函数实际上是对系统调用execve进行了封装,以满足不同用户的不同调用场景的。
下图为exec系列函数族之间的关系: