900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 009exec函数wait waitpid回收子进程

009exec函数wait waitpid回收子进程

时间:2022-05-04 05:13:54

相关推荐

009exec函数wait waitpid回收子进程

LINUX系统编程学习笔记

exec 子程序跳转,wait、waitpid 回收子程序1. exec 函数族1.1 exec 作用1.2 exec 函数族头文件包含及声明1.3 exec 函数跳转 demo1.4 execv、execvp使用方法2. 孤儿进程和僵尸进程2.1 孤儿进程2.2 孤儿进程demo2.3 僵尸进程2.4 僵尸进程demo3. wait 回收子进程终止信息3.1 头文件及函数声明3.2 status 宏函数3.2 wait 回收子进程demo4. waitpid 函数4.1 waitpid demo4.2 waitpid 循环回收多个子进程 demo

exec 子程序跳转,wait、waitpid 回收子程序

1. exec 函数族

1.1 exec 作用

fork创建子进程后执行的是和父进程相同的程序(可能靠if判断pid执行不同的分支结构),exec函数则能让子进程执行另一个程序。当进程调用exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。exec不会创建新进程,所以调用exec前后进程id并没有发生变化

将当前进程的.text、.data替换为所要加载的程序的 .text、.data,然后让进程从新的.text第一条指令开始执行,但进程 id 不变, 换核不换壳

说人话就是:exec跳转另一个.out程序且不返回!!!

1.2 exec 函数族头文件包含及声明

man exec

#include<unistd.h>int execl(const char* path, const char* arg, ... , NULL);// 自己定义文件路径,(绝对路径/相对路径)int execlp(const char* file, const char* arg, ... , NULL);// 在环境变量 PATH 中寻找 file 进行跳转int execv(const char* path, char* const argv[] , ... , NULL);int execvp(const char* file, char* const argv[] , ... , NULL);

exec函数一旦调用成功即执行新的程序,不返回。只有失败才返回,错误值-1,所以通常直接在exec函数后面进行 perror 和 exit 。

1.3 exec 函数跳转 demo

fork 创建子进程,子进程通过 exec 跳出实现 ls -l 打印的功能 或者 跳转到自己编写的程序(execl_test.out)当中

/* fork_execl.c */#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#include<string.h>int main(int argc, char *argv[]){pid_t pid = fork();if(pid == -1){perror("fork error");exit(0);}else if(pid == 0){//execlp("ls","ls", "-l", "-h", NULL); //给agrv[0] 传参execl("./execl_test.out","./execl_test.out", NULL); // 跳转到自己编译的程序中去execl("/bin/ls","ls", "-l", NULL);// 打印 ll 命令perror("exec error");exit(1);}else if(pid > 0){sleep(1);printf("I'm parent:%d\n", getpid());}return 0;}

实现 ls -l 功能:

自己编写的 execl_test.c 程序,编译。

#include<unistd.h>#include<fcntl.h>#include<stdio.h>#include<stdlib.h>int main(void){int fd;fd = open("ps.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);if(fd<0){perror("open ps.out error\n");exit(1);}dup2(fd, STDOUT_FILENO);execlp("ps","ps","aux", NULL);perror("execlp error\n");return 0;}

跳转到 execl_test.out 结果:

1.4 execv、execvp使用方法

char* argv[]={"ls", "-l", "-h", NULL};exevp("ls", argv);

2. 孤儿进程和僵尸进程

2.1 孤儿进程

父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿院

2.2 孤儿进程demo

#include<stdio.h>#include<unistd.h>#include<sys/wait.h>int main(void){pid_t pid;pid = fork();if (pid ==0){while (1){printf("I am child, my parent pid = %d\n", getppid());sleep(1);}}else if(pid > 0){printf("I am parent, my pid is %d\n", getpid());sleep(9);printf("----------parent going to die-----------\n");}else{perror("fork");return 1;}}

运行界面:

ps ajx 查看后台进程:父进程未死前:

父进程死亡后,子进程的父进程变为 init 进程,送入进程孤儿院:

2.3 僵尸进程

进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸进程(死亡未回收)

注:僵尸进程是不能使用kill命令清除的,因为僵尸进程已经终止,kill命令是用来终止进程的

(方法就是杀死他爹)

2.4 僵尸进程demo

/* zoom.c */#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/wait.h>int main(void){pid_t pid;pid = fork();if(pid == 0){printf("---child, my parent = %d, going to sleep 10s\n", getppid());sleep(10);printf("--------child die ---------\n");}else if(pid>0){while (1){printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);sleep(1);}}else{perror("fork");return 1;}return 0;}

编译运行:

子进程死亡前:

子进程死亡后,但未被父进程回收,变成僵尸进程:

3. wait 回收子进程终止信息

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用 wait 或 waitpid 获取这些信息,然后彻底清除掉这个进程。

一个进程的退出状态可以在 Shell 中用特殊变量 $? 查看,因为 Shell 是它的父进程,当它终止时 Shell 调用 wait

或 waitpid 得到它的退出状态同时彻底清除掉这个进程

父进程调用 wait 函数可以回收子进程终止信息。该函数有3个功能:

阻塞等待子进程退出;回收子进程残留资源获取子进程结束状态(退出原因);

3.1 头文件及函数声明

man 2 wait#include<sys/types.h>#include<sys/wait.h>pid_t wait(int* status)

其中,status (传出参数,用来保存退出信息) 可以通过宏函数来解析具体的含义

返回值

成功:返回子进程的ID

失败:返回-1

3.2 status 宏函数

WIFEXITED(status) 非0 --->进程正常结束WEXITSTATUS(status)上宏为真,使用此宏--->获取进程退出状态(exit的参数)WIFSIGNALED(status)非0---->进程异常终止WITERMSIG(status)上宏为真,使用此宏--->获取使进程终止的那个信号编号WIFSTOPPED(status)非0---->进程处于暂停状态WSTOPSIG(status)上宏为真,使用此宏---->取得使进程暂停的那个信号编号WIFCONTINUED(status)非0---->进程暂停后已经继续运行

特殊用法:

wpid = wait(NUll); //不关心子进程结束的原因

3.2 wait 回收子进程demo

/* 父进程等待子进程结束,并回收子进程demo */#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/wait.h>int main(void){pid_t pid,wpid;int status;pid = fork();if (pid ==0){printf("---child, my pid= %d, going to sleep 10s\n", getpid());sleep(10);printf("---------child die------------\n");return 73;// 子进程结束返回}else if(pid > 0){wpid = wait(&status);if (wpid == -1){perror("wait error\n");exit(1);}if (WIFEXITED(status)) //为真,说明子进程正常中断{printf("child exit with %d\n",WEXITSTATUS(status)); //调用子进程返回73}if(WIFSIGNALED(status)) // 为真,说明子进程是被信号终止{printf("child kill with signal %d\n", WTERMSIG(status));}printf("--------parent wait finish, child pid = %d\n", wpid);}else{perror("fork");return 1;}return 0;}

在程序运行过程中,kill -9 7196 杀死子程序:

4. waitpid 函数

作用同 wait,但可指定 pid 进程清理,可以不阻塞

pid_t waitpid(pid_t pid, int *status, int options);

返回值

0: 表示成功,返回回收子进程的pid

=0:函数调用时,参3 设置为WNOHANG(非阻塞),并且,没有子进程结束。

-1:失败,设置errno

!!!! 一次 wait/waitpid 函数调用,只能回收一个子进程

参数pid:

0: 回收指定ID的子进程

-1:回收任意子进程(相当于wait)

0:回收和当前调用waitpid一个组的所有子进程

<-1:回收指定进程组内的任意子进程

4.1 waitpid demo

父进程循环创建多个进程,然后用 waitpid 去回收第二个子进程

/* loop_waitpid.c */#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/wait.h>#include<pthread.h>#include<string.h>int main(int argc, char *argv[]){int i;pid_t pid,wpid, tmpid;for(i=0; i<5; i++){pid = fork();if(pid == 0)break;if (i ==2){tmpid = pid;printf("------pid = %d\n", tmpid);}}if(i == 5){sleep(5); //因为设置了非阻塞,所以父进程应该晚结束wpid = waitpid(tmpid, NULL, WNOHANG); //非阻塞wpid = waitpid(tmpid, NULL, 0); //阻塞if (wpid == -1){perror("waitpid error");exit(1);}printf("I'm parent, wait a child finish : %d \n", wpid);}else{sleep(i);printf("I'm %dth child, pid = %d\n",i+1, getpid());}return 0;}

注意!!!!!!

父进程和子进程之间全局变量不同!!!!!

4.2 waitpid 循环回收多个子进程 demo

#include<sys/wait.h>#include<pthread.h>#include<string.h>int main(int argc, char *argv[]){int i;pid_t pid, wpid;for(i=0; i<5; i++){if(pid = fork() == 0)break;}if(i == 5){while ((wpid = waitpid(-1, NULL, WNOHANG)) != -1){if (wpid > 0){printf("wait child %d\n", wpid);}else if(wpid == 0){sleep(1);continue; }}}else//sleep(i);printf("I'm %dth child\n",i+1);return 0;}

父进程循环创建5个子进程,父进程使用 while 循环非阻塞回收子进程

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。