exec系列中的系统调用都完成相同的功能(只是参数不同而已),它们把一个新程序装入调用进程的内存空间,来改变调用进程的执行代码,从而形成新进程。如果exec调用成功,调用进程将被覆盖,然后从新程序的入口开始执行,这样就产生了一个新的进程,但是它的进程标识符与调用进程相同。这就是说,exec没有建立一个与调用进程并发的新进程,而是用新进程取代了原来的进程。所以,在exec调用成功后,没有任何数据返回,这与fork()不同。下面给出了exec系列系统调用在linux系统库unistd.h中的函数声明:
int execl(const char *path,const char *arg,...);
int execlp(const char *file,const char *arg,...);
int execle(const char *path,const chr *arg,...,char * const envp[]);
int execv(const char *path,char * const argv[]);
int execvp(const char *file,char * const argv[]);
以execl()为例,execl()调用的参数均为字符型指针,第一个参数path给出了被执行的程序所在的文件名,它必须是一个有效的路径名,文件本身也必须是一个真正的可执行程序。第二个以及用省略号表示的其他参数一起组成了该程序执行时的参数表,按照linux的贯例,参数表的第一项是不带路径的程序文件名。被调用的程序可以访问这个参数表,它们相当于shell下的命令行参数。实际上,shell本身对命令的调用也是用exec调用来实现的。由于参数的个数是任意的,所以必须用一个NULL指针来标记参数表的结尾。下面给出一个使用execl调用来运行目录列表程序ls的例子:
#include
#include
int main()
{
printf("executing ls\n");
execl("/bin/ls","ls","-l",NULL);
//如果execl返回,说明其调用失败
perror("execl failed to run ls");
exit(1);
}
与它类似的是execlp(),它们的主要区别是:execlp()的第一个参数指向的是一个简单的文件名,而不是一个路径名,它通过检索shell环境变量PATH指出的目录来得到该文件名的路径前缀部分。
exec常用法:exec系统调用经常与fork()联合使用,我们可以先用fork建立一个子进程,然后在子进程中使用exec,这样就实现了父进程运行一个与其不同的子进程,并且父进程不会被覆盖。下例为fork和exec联用的例子:
#include
#include
#include
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("fork failed");
exit(1);
}
else if(0 == pid)
{
execl("/bin/ls","ls","-l","--color",NULL);
perror("execl failed");
exit(1);
}
else
{
wait(NULL);
printf("ls completed\n");
exit(0);
}
}
阅读(5101) | 评论(1) | 转发(0) |