在 Linux 中,使用子程序的基本流程如下:
创建子进程
使用 `fork()` 系统调用创建一个新的子进程。`fork()` 会创建一个与父进程几乎完全相同的副本,子进程从父进程那里继承数据段、代码段、堆栈、文件描述符等,但子进程有自己的进程 ID(PID)。
调用 exec
在子进程中调用 `exec` 系列系统调用来执行一个新的程序。`exec` 系列调用包括 `execl()`, `execv()`, `execle()`, `execve()` 等,它们的主要区别在于参数传递方式不同。
替换子进程的内存映像
`exec` 调用会替换子进程的整个内存空间,包括代码段、数据段、堆栈等,只保留进程的 PID 和一些特定属性。一旦执行 `exec`,子进程会从头开始执行新程序,原有的代码和数据将不再存在。
父进程继续执行
父进程在创建子进程后,保持不变,继续执行它的代码,直到调用 `wait()` 或 `waitpid()` 等待子进程结束。
```c
include include include int main() { char *argv[] = {"ls", "-l", NULL}; // 参数列表 char *envp[] = {"PATH=/bin", NULL}; // 环境变量 printf("执行 /bin/ls -l\n"); execve("/bin/ls", argv, envp); // 如果 execve 调用成功,以下代码将不会被执行 perror("execve"); return 1; } ``` 在这个示例中,`execve()` 函数用于执行 `/bin/ls` 程序,并传递参数列表 `argv` 和环境变量列表 `envp`。如果 `execve()` 调用成功,程序将从头开始执行 `/bin/ls`,而不会执行后续的代码。 建议 确保在调用 `exec` 系列函数之前,已经正确初始化了参数列表和环境变量列表。 如果需要传递大量参数或环境变量,可以考虑使用 `execvp()` 或 `execlp()` 函数,它们可以根据 `PATH` 环境变量自动搜索程序。 `exec` 系列函数会替换整个子进程的内存空间,因此在调用 `exec` 之后,原有的代码和数据将无法恢复。