系统编程-进程-exec系列函数超级详解(带各种实操代码)

系统编程-进程-exec系列函数超级详解(带各种实操代码)我的相关博文:系统编程-进程-close-on-exec机制PART1exec系列函数功能简介exec系列函数登场常规操作是先fork一个子进程,然后在子进程中调用exec系列函数执行新的目标程序,虽然exec系列函数执行成功不返回,但是我们仍然i要使用wait或waitpid让父进程给

大家好,欢迎来到IT知识分享网。

我的相关博文:

系统编程-进程-close-on-exec机制

 

PART1 

exec系列函数功能简介

系统编程-进程-exec系列函数超级详解(带各种实操代码)

 

exec系列函数登场

系统编程-进程-exec系列函数超级详解(带各种实操代码)

常规操作是先fork一个子进程,然后在子进程中调用exec系列函数执行新的目标程序,

虽然exec系列函数执行成功不返回,但是我们仍然i要使用wait或waitpid让父进程给该子进程收尸,否则将会产生一个僵尸进程(子进程死了,老爸没给收尸,子成为僵尸)!

并且,不论子进程内的exec系列函数执行成功或是失败,我们都要在父进程给对其收尸!

待实验,见实验1(实验1,使用execl),  思路:

让子进程内调用exec系列函数执行的新程序的生命周期大概是5秒,观察父进程wait成功且执行到wait后面的打印语句的时间,判断是否也为5秒。

 

该系列函数辨识方法

该系列函数都以“exec”为前缀,后面的字母有各自固定的含义,可以根据这点来进行区分,而无需强行记忆。看下图详解:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

补充知识点:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

读完上面的小结,我们可以分析出,例如execl,其第一个参数pathname,必须要求是绝对路径。

 

exec系列函数关系剖析

系统编程-进程-exec系列函数超级详解(带各种实操代码)

 

注意事项:

如果代码想下图这样写,因为exec函数执行出错,但是后续代码仍然会被执行,可是:当前进程的内存空间(堆、栈、数据区)可能已经被破坏,所以这种写法是不妥的!

系统编程-进程-exec系列函数超级详解(带各种实操代码)

上图代码不妥,应该修改为下图方式,即设置进程退出:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

同时,若exec执行成功,则后续代码不会被执行。

 

PART2

实验部分 

实验0

实验目的:execl错误使用展示

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h>

char* elf_name = "do cat"; char* path1 = "ls";      // 相对路径
char* path2 = "/bin/ls"; // 绝对路径

char* argv1 = "-al"; char* argv2 = "a.out"; int main(void) { int status = 0; pid_t pid; printf("main-process-pid: %ld\n", (long)getpid()); pid = fork(); if (pid < 0) { printf("fork error"); } else if (pid == 0) { printf("son-process-pid: %ld\n", (long)getpid()); if(execl(path1, elf_name, argv1, argv2, NULL)<0){
        perror("execl error"); exit(1); }else{ printf("execl %s success\n", elf_name); } } wait(NULL); printf("-------main process ending------\n"); return 0; }

编译运行:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

错误原因:execl的第一个参数不支持是相对路径,所以上述实验中execl的第一个参数应该是path2 .

 

实验1

实验目的1: execl使用展示

实验目的2:

虽然exec系列函数执行成功不返回,但是我们仍然要使用wait或waitpid让父进程给该子进程收尸,否则将会产生一个僵尸进程(子进程死了,老爸没给收尸,子成为僵尸)!

并且,不论子进程内的exec系列函数执行成功或是失败,我们都要在父进程给对其收尸!

让子进程内调用exec系列函数执行的新程序的生命周期大概是5秒,观察父进程wait成功且执行到wait后面的打印语句的时间,判断是否也为5秒。

屏蔽父进程内的wait函数与否将产生不同的效果,可使用ps -aux查看子进程是否变成了僵尸进程。

 

为了承接本文章上下文的连续性,将实验1分为三个小实验,逐步加深理解。

 

实验1-1: 验证僵尸进程的产生

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h>

char* elf_name = "do cat"; char* path1 = "ls";      // 相对路径
char* path2 = "/bin/ls"; // 绝对路径

char* argv1 = "-al"; char* argv2 = "a.out"; int main(void) { int status = 0; pid_t pid; printf("main-process-pid: %ld\n", (long)getpid()); pid = fork(); if (pid < 0) { printf("fork error"); } else if (pid == 0) { printf("son-process-pid: %ld\n", (long)getpid()); if(execl(path2, elf_name, argv1, argv2, NULL)<0){ perror("execl error"); exit(1); }else{ printf("execl %s success\n", elf_name); } } //wait(NULL); 这里不回收子进程
    while(1); return 0; }

在一个终端内编译运行:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

可见,子进程的进程ID是21018, 我们来看看在父进程不回收子进程,而子进程内又使用execl执行完毕了新程序后,是否会产生僵尸进程吧!

在另一个终端内查看:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

实验证实,子进程21018成为了僵尸进程。

同时,printf(“exec %s success\n”, elf_name)这句代码未打印,由此,我们也可以看出,通过execl执行的新程序正常执行是不会返回给主程序的,

实际上,通过整个exec系列函数成功执行新程序,都是不会返回给主程序的。

然而,父进程fork了子进程后就要遵循给其收尸的原则,即使使用了exec系列函数,也是如此。

 

相关知识点补充 – 进程状态及其标识 :

系统编程-进程-exec系列函数超级详解(带各种实操代码)

 

实验1-2

在实验1-1的代码基础上,父进程fork子进程后增加wait函数的使用,以用于对子进程的回收。此时我们重复实验1-1的操作过程,我们不会见到子进程成为僵尸进程。

 本实验和1-1极其相似,故省略。

 

实验1-3

hello.c :

#include <stdio.h> #include <unistd.h>

int main(){ sleep(5); printf("---<hello>elf, is ending---\n"); return 0; }

exec.c:

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h>

char* elf_name = "do hello"; char* path = "/home/lmw/MINE/Linux_C_exercise/fork/exec/hello"; // 绝对路径

int main(void) { int status = 0; pid_t pid; printf("main-process-pid: %ld\n", (long)getpid()); pid = fork(); if (pid < 0) { printf("fork error"); } else if (pid == 0) { printf("son-process-pid: %ld\n", (long)getpid()); if(execl(path, elf_name, NULL, NULL, NULL)<0){ perror("execl error"); exit(1); }else{ printf("execl %s success\n", elf_name); } } wait(NULL); printf("father waits son successfully \n"); return 0; }

编译运行:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

通过实验可见,可执行程序hello被成功执行起来了并且在5秒后退出(读者可以自行设置为6秒或者7秒或者8秒…),

同时,主进程内的wait调用也在5秒后成功返回(通过肉眼观察代码执行效果得出),表明在ecex函数装载的新程序结束后,父进程就对其展开收尸动作了。

本1-3实验可以进一步加深我们对fork exec wait等api进行混合使用的理解。

 

 

实验2 

实验目的:execvp使用展示( 本质和execl一样,都是为了调用新程序去执行,只是使用的方式不一样而已 )

系统编程-进程-exec系列函数超级详解(带各种实操代码)

根据前面的介绍,exec后面的v表示argv,所以execvp有一个参数是char* argv[]. 后面的p表示path,且支持相对路径,但是该相对路径必须要在系统的环境表中,

Linux下查看系统环境表中的路径:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

 

 

实验3  system介绍,自己编写功能更为强大的mysystem(自己手动调用exec系列函数可在需要时携带更多参数)。

系统编程-进程-exec系列函数超级详解(带各种实操代码)

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h>

char* test_cmd = "ps"; void mysystem(char* cmd){ pid_t pid; //printf("main-process-pid: %ld\n", (long)getpid());
 pid = fork(); if (pid < 0) { printf("fork error"); } else if (pid == 0) { //printf("son-process-pid: %ld\n", (long)getpid());
        if(execlp("bash", "I am bash", "-c", cmd, NULL)<0){ perror("execl error"); exit(1); } //printf("mysystem success \n");
 } wait(NULL); } int main(void) { mysystem(test_cmd); return 0; }

编译运行:

系统编程-进程-exec系列函数超级详解(带各种实操代码)

 

 

 

 

.

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/27697.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信