进程程序替换
进程替换原理
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。
exec函数
exec 函数的作用
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变
当调用了exec函数进行进程的替换的时候,若父子进程有共享的数据,那么子进程会发生写时拷贝,因此子进程的替换不会影响父进程
使用exec函数时需要用到头文件:
#include<unistd.h>
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[]);
参数理解
- int execl(const char *path, const char *arg, …): 这个函数接受一个程序路径 的环境变量path,需要把环境变量的路径进行传参,然后是一系列的参数,以NULL结尾。这些参数会传递给要执行的程序。注意,每个参数都需要作为一个单独的字符串传递,并以NULL结尾
举例:
execl("/usr/bin/bash", "bash","test.sh", NULL);
这里调用的第一个参数需要指明路径
- int execlp(const char *file, const char *arg, …): 与execl不同的是,但是它会在系统的 PATH 环境变量指定的目录中搜索可执行文件。其他方面与 execl 类似。
举例:
execlp("bash","bash","test.sh",NULL);
- int execle(const char *path, const char *arg, …,char *const envp[]): 这个函数接受一个程序路径 path,然后是一系列的参数,以NULL结尾,最后是一个环境变量数组 envp[]。通过传递 envp 参数,可以控制要执行的程序所使用的环境变量,这对于一些需要特定环境配置的程序是非常有用的。
举例:
//这里的环境变量需要自己组建并通过envp传参
execle("ps", "ps", "-ef", NULL, envp);
- int execv(const char *path, char *const argv[]): 这个函数与 execl 类似,但是参数以数组的形式传递,即参数数组 argv[] 包含了要传递给程序的参数,以NULL结尾。因此在使用此函数时需要提前定义argv[]数组
举例:
execv("/bin/ps", argv);
- int execvp(const char *file, char *const argv[]): 类似于 execv,但不需要传入完整画背景变量的路径,是它会在系统的 PATH 环境变量指定的目录中搜索可执行文件,相同点是需要利用argv[]数组进行传参
execvp("ls", argv);
- int execve(const char *path, char *const argv[], char *const envp[]): 这个函数与 execle 类似,但是参数以数组的形式传递,即参数数组 argv[] 包含了要传递给程序的参数,最后是一个环境变量数组 envp[],用于显式地传递环境变量给要执行的程序。,需要自己组装环境变量
execve("/bin/ps", argv, envp);
exec系列函数命名理解
- l(list) : 表示参数采用列表
- v(vector) : 参数用数组
- p(path) : 有p自动搜索环境变量PATH
- e(env) : 表示自己维护环境变量
程序替换函数exec函数的使用样例
下面我会分别展示如何在C语言中使用这几种exec
系列的函数。这些函数主要用于在当前进程中创建子进程,并让子进程执行一个新的程序,父进程等待子进程.
各个函数之间的区别主要在于如何指定要执行的程序和参数,以及环境变量。
每个例子都展示了如何使用子进程来调用不同的exec
函数来执行ls
命令,并列出当前目录下的文件。如果exec
函数调用成功,当前进程会被新程序替换,exec
函数调用后子进程的代码不会被执行。因此,如果看到了perror
的输出,那么就意味着调用失败了。
1. 使用execl
函数
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h> // 为了使用wait()
int