linux wait函数 : 处理僵尸进程(进程回收)
进程回收
在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要指进程控制块 PCB 的信息(进程号、退出状态、运行时间等)
父进程可以通过调用 wait 或 waitpid 得到它的退出状态同时彻底清除这个进程。
wait() 和 waitpid() 函数的功能一样,区别在于,wait() 函数会阻塞, waitpid() 可以设置不阻塞, waitpid() 还可以指定等待那个子进程结束
注意:一次 wait 或 waitpid 调用只能清理一个子进程,清理多个子进程应使用循环。
--wait函数
1 /* 2 man 2 wait 3 #include <sys/types.h> 4 #include <sys/wait.h> 5 pid_t wait(int* wstatus); 6 功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收子进程资源 7 参数: 8 int* wstatus 9 进程退出时的状态信息,传入的是一个 int 类型的地址, 传出参数 10 返回值: 11 - 成功: 返回被回收的子进程的 id 12 - 失败: -1(所有的子进程都结束,函数调用失败) 13 调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者收到一个不能被忽略的信号时,才被唤醒(继续执行) 14 如果没有子进程了,函数立刻返回,返回 -1, 如果子进程都已经结束了,也会立即返回, 返回 -1 15 */ 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <stdio.h> 19 #include <unistd.h> //fork 20 #include <stdlib.h> 21 int main() 22 { 23 //有一个父进程,创建5个子进程(兄弟) 24 pid_t pid; 25 26 for(int i = 0; i < 5; i++) 27 { 28 pid = fork();//如果不给子进程break 会产生 孙子进程 即 子进程的子进程 29 if(pid == 0) 30 { 31 break; 32 } 33 } 34 if(pid > 0) 35 { 36 //父进程 37 while(1) 38 { 39 printf("Parent process,pid = %d\n",getpid()); 40 int ret = wait(NULL);//不需要获取子进程状态 41 printf("Child die,pid = %d\n",ret);//失败 返回 -1 42 sleep(1); 43 } 44 } 45 else if(pid == 0) 46 { 47 //子进程 48 while(1) 49 { 50 printf("Child, pid = %d\n",getpid()); 51 sleep(1); 52 } 53 //kill -9 进程号 终端杀死进程 54 //若不执行 40行执行后 父进程会阻塞 执行kill杀死子进程后 父进程继续执行 即执行41行,但仅释放了一个行为 55 } 56 //ps aux 查询当前执行的 进程 57 return 0; 58 }
退出信息示例
1 if(pid > 0) 2 { 3 //父进程 4 while(1) 5 { 6 printf("Parent process,pid = %d\n",getpid()); 7 int st; 8 int ret = wait(&st); 9 if(ret == -1)//失败 返回-1 break; 10 { 11 break; 12 } 13 if(WIFEXITED(st)) 14 { 15 //是不是正常退出 16 printf("退出的状态码:%d\n",WEXITSTATUS(st));//输出:0 -- exit(0) 17 } 18 if(WIFSIGNALED(st)) 19 { 20 //是不是异常终止 21 printf("被那个信号干掉了:%d\n",WTERMSIG(st));//终端键入 kill -9 进程号 22 //输出 被那个信号干掉了: 9 23 } 24 printf("Child die,ret = %d, pid = %d\n",ret,getpid()); 25 sleep(1); 26 } 27 }
退出信息相关宏函数
1 WIFEXITED(status) //非0 进程正常退出 2 WEXITSTATUS(status) //如果上宏为真 获取进程退出的状态(exit的参数) 3 4 WIFSIGNALED(status) //非0 进程异常终止 5 WTERMSIG(status) //如果上宏为真,获取使进程终止的信号编号 6 7 WIFSTOPPED(status) //非0 进程处于暂停状态 8 WSTOPSIG(status) //如果上宏为真,获取使进程暂停的信号的编号 9 WIFCONTINUED(status) //非0,进程暂停后已经继续运行
--waitpid函数
1 /* 2 man 2 waitpid 3 ps ajx : 查询 进程的 pid ppid 进程组 4 进程组 A有BCD三个子进程 ABC一个组 D可以分给其他组 因此 释放A组的子进程 D没有被释放 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 pid_t waitpid(pid_t pid, int* wstatus, int options); 8 功能:回收指定进程号的子进程,可以设置是否阻塞 9 参数: 10 - pid: 11 pid > 0: 某个子进程的pid 12 pid = 0: 回收当前 进程组 的所有子进程 13 pid = -1: 回收所有的子进程,相当于 wait() ***最常用*** 14 pid < -1: 某个 进程组 的 组id的 绝对值,回收指定进程组中的子进程 15 - options:设置阻塞或者非阻塞 16 0:阻塞 17 WNOHANG():非阻塞 18 返回值: 19 > 0: 返回子进程的id 20 = 0: options = WNOHANG,表示还有子进程活着 21 = -1: 错误,或者没有子进程 22 */ 23 #include <sys/types.h> 24 #include <sys/wait.h> 25 #include <stdio.h> 26 #include <unistd.h> //fork 27 #include <stdlib.h> 28 int main() 29 { 30 //有一个父进程,创建5个子进程(兄弟) 31 pid_t pid; 32 33 for(int i = 0; i < 5; i++) 34 { 35 pid = fork();//如果不给子进程break 会产生 孙子进程 即 子进程的子进程 36 if(pid == 0) 37 { 38 break; 39 } 40 } 41 if(pid > 0) 42 { 43 //父进程 44 while(1) 45 { 46 printf("Parent process,pid = %d\n",getpid()); 47 int st; 48 int ret = waitpid(-1,&st,0);//默认为阻塞状态 49 if(ret == -1) 50 { 51 break; 52 } 53 if(WIFEXITED(st)) 54 { 55 //是不是正常退出 56 printf("退出的状态码:%d\n",WEXITSTATUS(st));//输出:0 -- exit(0) 57 } 58 if(WIFSIGNALED(st)) 59 { 60 //是不是异常终止 61 printf("被那个信号干掉了:%d\n",WTERMSIG(st));//终端键入 kill -9 进程号 62 //输出 被那个信号干掉了: 9 63 } 64 printf("Child die,ret = %d, pid = %d\n",ret,getpid()); 65 sleep(1); 66 } 67 } 68 else if(pid == 0) 69 { 70 //子进程 71 while(1) 72 { 73 printf("Child, pid = %d\n",getpid()); 74 sleep(1); 75 } 76 exit(0); 77 } 78 return 0;//exit(0); 79 }
此时终端显示:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)