回顾
对于进程,我们已经有了初步的了解,我们学会了进程的终止,进程的等待,还有如果创建子进程。
这次,我们来学习如何把一个进程运行的代码和数据替换成其他的代码和数据。
进程的替换
为什么要进程替换,在某些场景下,我们需要创建子进程,并且想让子进程运行其他的程序而不是父进程的代码,所以就有了进程的替换。
man 3 手册查看的是库提供的函数
man 3 execl //使用man手册查看execl函数
#include <unistd.h>
extern char **environ;
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 execvpe(const char *file, char *const argv[], char *const envp[]);
man 2 手册查看的是系统提供的函数
man 2 execve
#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
实际上这些函数的用法差异并不大,只要掌握了命名风格,就很好理解。
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量
1.execl
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
if(fork() == 0)
{
//子进程
//路径 //命令行参数(以NULL结尾)
execl("/usr/bin/ls","ls","-a","-l",NULL);
printf("hello world\n");
}
printf("i am father\n");
pid_t ret = wait(NULL);
if(ret >0)
{
printf("father wait success!\n");
}
else{
printf("father wait fail\n");
exit(1);
}
return 0;
}
使用fork创建子进程,在子进程中使用execl函数替换为其他程序。
先看看execl的参数
int execl(const char *path, const char *arg, ...);
path是一个字符串,而这个字符串就是我们想要替换的程序的路径
arg则是可变参数,并且它也是字符串。它们则是该程序的名字+你想要的命令行参数,并且记住以NULL结尾。
从输出结果来看,它输出了ls -a -l 的内容,而这些,就是我们的子进程运行的,子进程替换成了ls -a -l 指令进程。
2.execv
execv与execl不同的地方则是它们的第二个参数,execl是字符串的可变参数,execv的第二个参数是一个指针数组。
int execv(const char *path, char *const argv[]);
而execv 的argv只不过就是把所有的命令行参数整合成了一个数组,与execl并没有太大的区别。
3.execlp
int execlp(const char *file, const char *arg, ...);
execlp在命名上execl多了一个p,而这个p的含义就是 它会自己去自动搜索PATH环境变量中的程序。
所以execlp就是直接在PATH环境变量中找对应的程序。
4.execvp
int execvp(const char *file, char *const argv[]);
如果你理解了上面的execlp,那么execvp也很好理解了,它就可以自动在PATH环境变量中寻找对应的程序。
相信不难理解。
5.execle
从命名上比execl多了一个e,而e的含义就是可以给替换的进程 传入你想传入的环境变量。
从参数上,它多了一个envp的指针数组,这个指针数组就是你想传入的环境变量。
int execle(const char *path, const char *arg, ..., char * const envp[]);
我们写一个等会需要替换的代码,它会输出它所有的环境变量。
Makefile 同时编译两个C语言进程的方法
execle就是需要自己组装环境变量,就是把环境变量塞入需要替换的进程!
6.execve
int execve(const char *filename, char *const argv[], char *const envp[]);
也很好理解,在execv的基础上多了一个e的功能。
7.execvep
从命名风格看,是不是就知道它怎么使用了呢?
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量
这里就不再做演示了。
总结
虽然进程的替换有很多函数接口,但是,实际上他们的用法都是大同小异,理解它们的命名风格,就懂了。