900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 进程之wait函数和waitpid函数

进程之wait函数和waitpid函数

时间:2018-12-10 07:49:50

相关推荐

进程之wait函数和waitpid函数

一个进程终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或者waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在shell中用特殊变量$?查看,因为shell是它的父进程,当它终止时,shell调用wait或者waitpid得到它的退出状态,同时彻底清除掉这个进程。

1 wait回收子进程和异常终止信号

wait函数

// wait函数: 回收子进程退出资源, 阻塞回收任意一个。pid_t wait(int *status)// 参数:(传出) 回收进程的状态。// 返回值:成功: 回收子进程的pid// 失败: -1, errno// 函数作用1: 阻塞等待子进程退出【等子进程死亡,回收】// 函数作用2: 清理子进程残留在内核的 pcb 资源// 函数作用3: 通过传出参数,得到子进程结束状态

下面这个例子,使用wait来阻塞回收子进程

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/wait.h>int main(int argc, char *argv[]){pid_t pid, wpid;int status;pid = fork();if (pid == 0){printf("I'm child, my pid = %d, my parent pid = %d\n", getpid(), getppid());sleep(9);printf("I'm child, I'm going to die\n");}else if (pid > 0){// 父进程回收子进程wpid = wait(&status);if (wpid == -1){perror("wait error\n");exit(1);}printf("parent wait finish:%d\n", wpid);}else if (pid == -1){perror("fork error\n");exit(1);}return 0;}

执行

改进

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/wait.h>int main(int argc, char *argv[]){pid_t pid, wpid;int status;pid = fork();if (pid == 0) {printf("I'm child,my pid = %d, my parent = %d\n", getpid(), getppid());sleep(10);printf("---------------I'm going to die-------------------\n");// 特殊值,演示正常退出的返回值return 73;}else if (pid > 0) {// 父进程回收子进程 如果子进程未终止,父进程会阻塞在这个函数上// wpid = wait(NULL); // 不关心子进程结束原因wpid = wait(&status);if (wpid == -1) {perror("wait error\n");exit(1);}// 为真if (WIFEXITED(status)) {// 说明子进程正常终止printf("child exit with %d\n", WEXITSTATUS(status));}// 为真,说明子进程被信号终止if (WIFSIGNALED(status)) {printf("child is killed signal with %d\n",WTERMSIG(status));}printf("parent wait finish:%d\n", wpid);} else if (pid == -1) {perror("fork error\n");exit(1);}return 0;}

status的作用:

获取子进程正常终止值:WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。获取导致子进程异常终止信号:WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号

man 2 wait # 查看函数

执行

异常退出

2waitpid回收子进程

waitpid函数

// waitpid函数: 指定某一个进程进行回收。可以设置非阻塞。waitpid(-1, &status, 0) == wait(&status);pid_t waitpid(pid_t pid, int *status, int options)// 参数:// pid:指定回收某一个子进程pid// > 0: 待回收的子进程pid// -1:任意子进程// 0:同组的子进程。// status:(传出) 回收进程的状态。// options:WNOHANG 指定回收方式为,非阻塞。// 返回值:// > 0 : 表成功回收的子进程 pid// 0 : 函数调用时, 参3 指定了WNOHANG。并且,没有子进程结束。// -1: 失败。errno

一次wait/waitpid函数调用,只能回收一个子进程。上一个例子,父进程产生了5个子进程,wait会随机回收一个,捡到哪个算哪个。

父进程先回收,子进程后结束

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/wait.h>int main(int argc, char *argv[]){int i;pid_t pid, wpid;for (i = 0; i < 5; i++){pid = fork();if (pid == 0){break;}}if(i == 5){// sleep(5);// wait(NULL); // 一次wait和waitpid调用,只能回收一个子进程,无差别回收wpid = waitpid(-1, NULL, WNOHANG);if (wpid == -1){perror("waitpid error\n");exit(1);}printf("I'm parent, with a child finish:%d\n", wpid);}else{sleep(i);printf("I'm %dth child\n", i + 1);}return 0;}

执行

父进程休眠,等待子进程结束,回收,即放开注释的sleep(5),打印pid

指定某一个进程回收。

(1)阻塞回收

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/wait.h>int main(int argc, char *argv[]){int i;pid_t pid, wpid, tpid;for (i = 0; i < 5; i++){pid = fork();if (pid == 0){ // 循环期间,子进程不forkbreak;}if(i == 2){// 父进程执行tpid = pid; // 保存子进程pidprintf("----------pid = %d\n", tpid);}}if(i == 5){// sleep(5);// wait(NULL); // 一次wait和waitpid调用,只能回收一个子进程,无差别回收printf("-----parent, before waitpid pid = %d\n", tpid);wpid = waitpid(tpid, NULL, 0); // 指定一个进程回收, 阻塞回收if (wpid == -1){perror("waitpid error\n");exit(1);}printf("I'm parent, with a child finish:%d\n", wpid);}else{sleep(i);printf("I'm %dth child, pid = %d\n", i + 1, getpid());}return 0;}

执行

这里会和中断提示符混在一起,并且不会结束。

(2)非阻塞+时延:这样终端提示符就不会混在输出里。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/wait.h>int main(int argc, char *argv[]){int i;pid_t pid, wpid, tpid;for (i = 0; i < 5; i++){pid = fork();if (pid == 0){ // 循环期间,子进程不forkbreak;}if(i == 2){// 父进程执行tpid = pid; // 保存子进程pidprintf("----------pid = %d\n", tpid);}}if(i == 5){sleep(5);// wait(NULL); // 一次wait和waitpid调用,只能回收一个子进程,无差别回收printf("-----parent, before waitpid pid = %d\n", tpid);wpid = waitpid(tpid, NULL, WNOHANG); // 指定一个进程回收, 不阻塞 if (wpid == -1){perror("waitpid error\n");exit(1);}printf("I'm parent, with a child finish:%d\n", wpid);}else{sleep(i);printf("I'm %dth child, pid = %d\n", i + 1, getpid());}return 0;}

执行

3 waitpid回收多个子进程

wait、waitpid 一次调用,回收一个子进程。

想回收多个。while

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/wait.h>int main(int argc, char *argv[]){int i;pid_t pid, wpid;for (i = 0; i < 5; i++){pid = fork();if (pid == 0){ // 循环期间,子进程不forkbreak;}}if(i == 5){/* // 使用阻塞方回收子进程while((wpid = waitpid(-1, NULL, 0))) {printf("wait child %d\n",wpid);}*/// 非阻塞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, pid = %d\n", i + 1, getpid());}return 0;}

执行

全部回收了。

想暴力回收子进程

kill -9 父进程号

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