进程替换讲解
1. 基本概念
1.1 进程替换 vs. 进程创建
- 进程创建:使用
fork()
或clone()
等系统调用创建一个新的子进程,子进程是父进程的副本,拥有相同的代码和数据。 - 进程替换:使用
exec
系列函数在当前进程中加载并执行一个新的程序,替换掉当前进程的映像,但保留PID、文件描述符等资源。
1.2 exec
系列函数
exec
系列函数用于在当前进程中执行一个新程序。常见的exec
函数包括:
这些函数的命名规则如下:
- 前缀:
exec
- 中间部分:
l
(list):参数以列表形式传递。v
(vector):参数以数组形式传递。
- 后缀:
e
:允许传递环境变量。p
:使用PATH
环境变量来查找可执行文件。
2. 常用的exec
函数
2.1 execl()
函数原型:
#include <unistd.h>int execl(const char *path, const char *arg, ... /* (char *) NULL */);
参数:
path
:要执行的可执行文件的路径。arg
:第一个参数,通常是程序名。...
:可变参数列表,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>int main() {printf("Before execl\n");execl("/bin/ls", "ls", "-l", NULL);// 如果execl成功,以下代码不会执行perror("execl failed");return 1;
}
2.2 execv()
函数原型:
#include <unistd.h>int execv(const char *path, char *const argv[]);
参数:
path
:要执行的可执行文件的路径。argv
:参数数组,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>int main() {char *args[] = { "ls", "-l", NULL };printf("Before execv\n");execv("/bin/ls", args);// 如果execv成功,以下代码不会执行perror("execv failed");return 1;
}
2.3 execlp()
函数原型:
#include <unistd.h>int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
参数:
file
:可执行文件名,会在PATH
环境变量中查找。arg
:第一个参数,通常是程序名。...
:可变参数列表,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>int main() {printf("Before execlp\n");execlp("ls", "ls", "-l", NULL);// 如果execlp成功,以下代码不会执行perror("execlp failed");return 1;
}
2.4 execvp()
函数原型:
#include <unistd.h>int execvp(const char *file, char *const argv[]);
参数:
file
:可执行文件名,会在PATH
环境变量中查找。argv
:参数数组,以NULL
结尾。
例子:
#include <stdio.h>
#include <unistd.h>int main() {char *args[] = { "ls", "-l", NULL };printf("Before execvp\n");execvp("ls", args);// 如果execvp成功,以下代码不会执行perror("execvp failed");return 1;
}
2.5 execle()
函数原型:
#include <unistd.h>int execle(const char *path, const char *arg, ... /* (char *) NULL, char * const envp[] */);
参数:
path
:要执行的可执行文件的路径。arg
:第一个参数,通常是程序名。...
:可变参数列表,以NULL
结尾。envp
:环境变量数组。
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main() {char *env[] = { "PATH=/bin", NULL };printf("Before execle\n");execle("/bin/ls", "ls", "-l", NULL, env);// 如果execle成功,以下代码不会执行perror("execle failed");return 1;
}
2.6 execvpe()
#include <unistd.h>int execvpe(const char *file, char *const argv[], char *const envp[]);
参数
-
file
:要执行的可执行文件的名称。如果file
中包含斜杠 (/
),则将其视为路径名,直接尝试执行。(如果file
不包含斜杠,则会在PATH
环境变量指定的目录中查找可执行文件。) -
argv
:参数数组,以NULL
结尾。argv[0]
通常是程序名。 -
envp
:环境变量数组,以NULL
结尾。每个环境变量以"NAME=VALUE"
的形式表示。
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main() {// 要执行的程序及其参数char *args[] = { "printenv", "MY_VAR", NULL };// 自定义环境变量char *env[] = { "MY_VAR=HelloWorld", "PATH=/bin:/usr/bin", NULL };printf("Before execvpe\n");// 执行程序if(execvpe("printenv", args, env) == -1) {perror("execvpe failed");exit(1);}// 如果 execvpe 成功,以下代码不会执行return 0;
}
2.7 execve()(这个上面查库没有,要单独查)
函数原型:
参数:
pathname
:要执行的可执行文件的路径。argv
:参数数组,以NULL
结尾。envp
:环境变量数组。
例子:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main() {char *args[] = { "ls", "-l", NULL };char *env[] = { "PATH=/bin", NULL };printf("Before execve\n");execve("/bin/ls", args, env);// 如果execve成功,以下代码不会执行perror("execve failed");return 1;
}
3. 错误处理
大多数exec
函数在成功时不会返回,如果失败则返回-1,并设置errno
变量。常见的错误包括:
- ENOENT:文件不存在。
- EACCES:权限不足。
- ENOEXEC:可执行文件格式错误。
例子:
#include <stdio.h>
#include <unistd.h>int main() {if(execl("/bin/ls", "ls", "-l", NULL) == -1) {perror("execl failed");}// 如果execl成功,以下代码不会执行return 1;
}