程序替换的目的
在使用fork创建了子进程之后,我们经常需要对子进程进行程序替换,去让子进程干别的事情。替换之后,进程的用户空间代码和数据完全被新程序替换。
本质上来说就是替换一个pcb对应代码和数据,加载新代码和数据到这个pcb上,更新页表,虚拟地址空间等相关信息,让这个pcb开始调度这个新程序。
值得注意的是程序替换并不是创建新的进程因此被替换的进程id是不变的。
举个例子:
我们在shell程序中使用ls命令的时候就发生了程序替换.
- 在终端输入ls -l
- shell创建进程对输入字符串解析,并解析完毕。
- 找到解析到的ls程序 传入-l参数,并执行,
- 执行完毕之后,终端显示出我们想要的数据,shell进程结束。
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[]);
这些函数都是替换函数,替换成功后加载新的程序,从启动代码开始执行!
辅助记忆
代码
#include <unistd.h>
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-ef", NULL);
// 带p的,可以使用环境变量PATH,无需写全路径
execlp("ps", "ps", "-ef", NULL);
// 带e的,需要自己组装环境变量
execle("ps", "ps", "-ef", NULL, envp);
execv("/bin/ps", argv);
// 带p的,可以使用环境变量PATH,无需写全路径
execvp("ps", argv);
// 带e的,需要自己组装环境变量
execve("/bin/ps", argv, envp);
exit(0);
}