首页 > 代码库 > 第十九篇:处理僵尸进程的两种经典方法
第十九篇:处理僵尸进程的两种经典方法
前言
如果父进程没有结束,而子进程终止了。那么在父进程调用 wait 函数回收这个子进程或者父进程终止以前,这个子进程将一直是僵尸进程。
本文将提供两种方法处理这个问题。
方法一:父进程回收法
wait函数将使其调用者阻塞,直到其某个子进程终止。故父进程可调用wait函数回收其僵尸子进程。除此之外,waitpid函数提供更为详尽的功能( 增加了非阻塞功能以及指定等待功能 ),请读者自行查阅相关资料。
代码实现
1 #include <unistd.h> 2 #include <sys/wait.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 int main() 7 { 8 int pid; 9 int *status;10 11 printf("%s\n", "启动父进程");12 13 if ((pid = fork()) < 0) {14 printf("%s\n", "创建子进程失败");15 exit(1);16 }17 else 18 if (pid ==0) {19 printf("%s\n", "进入子进程");20 sleep(4);21 // 终止子进程22 exit(0);23 }24 else {25 // 进入父进程26 // 回收僵尸子子进程27 wait(status);28 printf("%s\n", "回收完毕");29 }30 31 exit(0);32 }
运行测试
结果分析
第三行的“回收完毕”是在程序执行四秒后才显示的。这说明尽管我将子进程阻塞了4秒,父进程并不会先于子进程终止。因为它调用了wait函数,故需要等待一个子进程结束并将其回收,否则就一直阻塞在那里。
方法二:init进程回收法
上面的这种解决方案需要父进程去等待子进程,但在很多情况下,这并不合适,因为父进程也许还有其他任务要做,不能阻塞在这里。在讲述下面这种不用父进程等待就能完成回收子进程的方法之前,先请明白以下两个概念:
1. 如果父进程先于子进程结束,那么子进程的父进程自动改为 init 进程。
2. 如果 init 的子进程结束,则 init 进程会自动回收其子进程的资源而不是让它变成僵尸进程。
代码实现
1 #include "apue.h" 2 #include <sys/wait.h> 3 4 int 5 main(void) 6 { 7 pid_t pid; 8 9 if ((pid = fork()) < 0) { // 创建第一个子进程10 err_sys("fork error");11 } else if (pid == 0) { // 进入第一个子进程12 if ((pid = fork()) < 0) // 创建第二个子进程13 err_sys("fork error");14 else if (pid > 0) // 进入第一个子进程 15 exit(0); // 终止第一个子进程 16 // 第二个子进程在睡眠2S后才执行,这样一般情况下第一个子进程会先终止。17 sleep(2);18 // 这时,第一个子进程肯定终止了,那么它的父进程就自动变成了init。19 printf("second child, parent pid = %d\n", getppid());20 exit(0);21 }22 23 // 父进程等待并回收第一个子进程24 if (waitpid(pid, NULL, 0) != pid) 25 err_sys("waitpid error");26 27 // 父进程执行到这里以后,可以退出,也可以执行其他的任务。28 // 对于刚才那第二个子进程,它继承了父进程的资源,同时它终止后也会被init进程回收,29 // 不会成为僵尸进程。30 exit(0);31 }
说明
1. fork创建子进程以后,子进程拥有的是父进程的一个资源副本,而不是和它共享资源。
2. 子进程终止后变成僵尸进程并不是系统BUG,而是因为子进程终止后,其一些信息操作系统或者用户以后还可能会用到。
第十九篇:处理僵尸进程的两种经典方法
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。