据说
顺便问一句,
fork
系统调用创建一个调用进程的克隆,然后(通常)子进程会发出execve
系统调用来改变其映像并运行新进程。为什么要这样做呢?顺便问一句,
execve
代表什么?两步的原因是为了灵活性。在这两个步骤之间,您可以修改子进程的上下文,新的exec'ed程序将继承该上下文。
您可能想要更改的一些内容包括:
如果您没有拆分fork和exec,而是使用单个类似于spawn的系统调用,则需要为每个这些进程属性提供参数,如果您希望在子进程中对它们进行不同设置。例如,请参见Windows API中CreateProcess的参数列表。
通过fork/exec,在调用新的程序之前,您可以更改您想要的任何可继承进程属性。
设置文件描述符是更改子进程上下文中较常见的操作之一。如果您想捕获程序的输出,通常会使用pipe(2)系统调用在父进程中创建一个管道,在fork(2)之后,在父进程中关闭写端口,并在子进程中关闭读端口,然后调用execve(2)。(您还将使用dup(2)将管道的子端口设置为文件描述符1(标准输出))。这在单个系统调用中可能是不可能或受限制的。
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[]);
每个步骤都相对简单。
在Unix中,你的进程有两个部分 - 一个只读的内存区域,包含应用程序代码("文本"),以及读写的内存区域("数据")。
fork克隆了读写区域,保留文本页不变。现在你有两个运行同一代码的进程。它们通过寄存器值(来自fork的返回值)不同而不同,这将父进程和子进程分开。
exec替换了文本页,保留数据页不变。有许多形式的exec,取决于你传递多少环境信息给它。请参见http://linux.die.net/man/3/exec以获取其他变体的列表。
execve
是什么意思?C语言中的exec函数有6个变体,它们分别是exec{l,v}{,e,p}
。详情请参见下面的函数原型。
命令行参数
v
- 命令行参数作为指针数组(vector)传递给函数。l
- 命令行参数被单独传递(list)给函数。环境变量(可选)
e
- 一个指向e环境变量的指针数组被显式地传递给新进程映像。定位要执行的文件(可选)
p
- 使用PATH环境变量查找要执行的文件名中的文件参数。int execl (char const *path, char const *arg0, ...);
int execle(char const *path, char const *arg0, ..., char const *envp[]);
int execlp(char const *file, char const *arg0, ...);
int execv (char const *path, char const *argv[]);
int execve(char const *path, char const *argv[], char const *envp[]);
int execvp(char const *file, char const *argv[]);