进程控制之exec函数


用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈段。

有6种不同的exec函数可供使用,它们常常被统称为exec函数。这些exec函数使得UNIX进程控制原语更加完善。用fork可以创建新进程,用exec可以执行新程序。exit函数和两个wait函数处理终止和等待终止。这些是我们需要的基本的进程控制原语。

#include <unistd.h>

 execl(   *pathname,   *arg0, ...  execv(   *pathname,  * execle(   *pathname,   *arg0, ...  execve(   *pathname,  * argv[],  * execlp(   *filename,   *arg0, ...  execvp(   *filename,  *-,若成功则不返回值

这些函数之间的第一个区别是前4个取路径名作为参数,后两个(execlp和execvp,p表示PATH,个人理解)则取文件名作为参数当指定filename作为参数时

  • 如果filename中包含了/,则将其视为路径名。
  • 否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件。

PATH变量包含了一张目录表(称为路径前缀),目录之间用冒号(:)分隔。例如name = value环境字符串:

PATH=/bin:/usr/bin:/usr/local/bin/:.

指定在4个目录中进行搜索。最后的路径前缀(.)表示当前目录。(零长前缀也表示当前目录。在value的开始处可用:表示,在行中间则要用::表示,在行尾则以:表示。)

如果execlp或execvp使用路径名前缀中的一个找到了一个可执行文件,但是该文件不是由连接编辑器产生的机器可执行文件,则认为该文件是一个shell脚本,于是试着调用/bin/sh,并以该filename作为shell的输入。

第二个区别与参数表的传递有关(l表示list,v表示矢量vector)。函数execl、execlp和execle要求将新程序的每个命令行参数都说明为一个单独的参数。这种参数表以空指针结尾。对于另外三个函数(execv、execvp和execve),则应先构造一个指向各参数的指针数组,然后将该数组地址作为这三个函数的参数。

在ISO C原型之前,对execl、execle和execlp这三个函数表示命令行参数的一般方法是:

char *arg0, char *arg1, …, char *argn, (char *)0

应当特别指出的是:在最后一个命令行参数之后跟了一个空指针。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整型参数。如果一个整型数的长度与char *的长度不同,那么exec函数的实际参数就将出错。

最后一个区别与向新程序传递环境表相关。以e结尾的两个函数(execle和execve)可以传递一个指向环境字符串指针数组的指针。其他四个函数则使用调用进程中的environ变量为新程序复制现有的环境。通常,一个进程允许将其环境传播给其子进程,但有时也有这种情况,即进程想要为子进程指定某一个确定的环境。

在使用ISO C原型之前,execle的参数是:

char *pathname, char *arg0, …, char *argn, (char *)0, char *envp[]

从中可见,最后一个参数是指向环境字符串的各字符指针构成的数组的地址。而ISO C原型中,所有命令行参数、空指针和envp指针都用省略号(...)表示。

这6个exec函数名中的字符说明:字母p表示该函数取filename作为参数,并且用PATH环境变量寻找可执行文件。字母l表示该函数取一个参数表,它与字母v互斥。字母v表示该函数取一个argv[]矢量。字母e表示该函数取envp[]数组,而不使用当前环境。

                                          表8-6 6个exec函数之间的区别

<sys/wait.h> *env_init[] = { , ((pid = fork()) < (pid == ) (execle(, , , , ( *), env_init) < (waitpid(pid, NULL, ) < ((pid = fork()) < (pid == ) (execlp(, , , ( *)) <

注意,我们将第一个参数(新程序中的argv[0])设置为路径名的文件名分量。某些shell将此参数设置为完整的路径名。这只是一个惯例。我们可将argv[0]设置为任何字符串。

程序清单8-8中要执行的程序echoall示于程序清单8-9中。这是一个很普通的程序,它回送其所有命令行参数及全部环境表。

程序清单8-9 回送所用命令行参数和所有环境字符串



 argc,  *        **  **(i=; i<argc; i++)   (ptr = environ; *ptr != ; ptr++)    , *

执行程序清单8-8得到

[root@localhost apue]# ./prog8-==/]: only ====/bin/

 

最后总结一下使用exec函数时需要考虑哪些参数:首先,要执行的新程序名(带不带路径);其次,命令行参数(列表形式还是指针数组形式);最后,环境表(要不要传递环境表)

 

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

相关内容