exec函数
1. exec函数作用
用fork创建子进程后执行的是和父进程相同的程序,可以通过if判断pid的返回值让子进程执行不同的代码分支,这样设计程序不灵活。通过调用exec函数,用新程序将子进程的用户空间代码和数据替换,直接去执行新程序。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
2. execc族函数原型
其实有六种以exec开头的函数,统称exec函数:
1. #include <unistd.h> 2. 3. int execl(const char *path, const char *arg, ...); 4. 5. int execlp(const char *file, const char *arg, ...); 6. 7. int execle(const char *path, const char *arg, ..., char *const envp[]); 8. 9. int execv(const char *path, char *const argv[]); 10. 11. int execvp(const char *file, char *const argv[]); 12. 13. int execve(const char *path, char *const argv[], char *const envp[]);
exec函数特点:
1.exec函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。
2.exec函数替换掉当前进程的用户空间,包括堆栈空间、代码段
3. 从code理解exec函数的作用
code 1 :
1. #include <stdio.h> 2. #include <unistd.h> 3. 4. 5. int main(void) 6. { 7. printf("hello.\n"); 8. execl("/bin/ls", "ls", "-l", NULL); 9. printf("world.\n"); 10. return 0; 11. }
执行结果:
分析:
可以看到没有执行 printf(“world.\n”);
这是因为/bin/ls加载到用户用户空间替换了原来代码段,所以execl下面的代码就不会执行了。所以程序是从ls的return 0退出程序的。
code 2 :
1. include <stdio.h> 2. #include <unistd.h> 3. #include <stdlib.h> 4. 5. int main(void) 6. { 7. pid_t pid; 8. pid = fork(); 9. 10. if(pid == 0) 11. { 12. /*in child*/ 13. execl("/usr/bin/firefox", "firefox", "www.baidu.com", NULL); 14. } 15. else if(pid > 0) 16. { 17. /*in parent*/ 18. while(1) 19. { 20. printf("I am parent process\n"); 21. sleep(1); 22. } 23. } 24. else 25. { 26. perror("fork"); 27. exit(1); 28. } 29. 30. return 0; 31. }
程序执行之后,父进程每隔1S循环打印你, 子进程调用firefox去打开网页。具体关系如下图。
重新打开一个终端,ps -aux可以看到
子进程加载新的程序不再显示为a.out
4. exec函数辨析
execl与execlp
1. execl("/bin/ls", "ls", "-l", NULL); 2. 3. execlp("ls", "ls", "-l", NULL);
execl要给全执行进程的路径,而execlp除了在当前路径下找,还可以去PATH环境变量底下找。p就是去环境变量底下找,不加p就是在当前路径下找,所以要给全路径
execv与execvp
这两个函数的功能跟excel与execlp的功能一样,只是将参数列表以数组指针的方式给出。
还是用上面执行ls举例
1. char *argvv[] = {“ls”, “-l”, NULL}; 2. 3. execv(“/bin/ls”, argvv); execvp(“ls”, argvv);char *argvv[] = {“ls”, “-l”, NULL}; 4. 5. execv(“/bin/ls”, argvv); execvp(“ls”, argvv);
execle execve中添加了一个替换环境变量的参数,在加载新的程序的时候,我们可以不用原来的环境变量。(这两个函数实际用的很少)