解析僵尸进程与孤儿进程
来源:互联网 发布:逆战磁暴矩阵 编辑:程序博客网 时间:2024/05/22 08:21
一、僵尸进程与孤儿进程的定义
我们知道一个子进程如果要结束,其内核释放进程的所有资源,但是还保存了一部分资源供父进程使用(是一个被称之为僵尸进程的数据结构,包含有进程号、运行时间、退出状态等,它需要父进程去处理),所以其父进程要调用wait或者waitpid获取子进程的状态信息,然而如果父进程没有调用这个信息会发生什么情况呢?
- 如果父进程没有调用这个信息,那么这段信息将会被一直占用,但是系统中的资源是有限的,如果大量资源被占用,此时将无法产生新的信息。
僵尸进程
一个进程如果创建出子进程,如果此时子进程退出,而父进程没有进行善后工作(wait与waitpid获取子进程状态信息),那么此时子进程的进程描述符仍然保存在系统中。
孤儿进程
如果一个父进程退出,它的子进程(有一个或者多个)还在,那么子进程将成为孤儿进程,这个时候这些孤儿进程会被1号进程,也就是init进程所收养,并且由init进程完成善后工作(状态收集)。
二、解决方法
由于孤儿进程在最后都会被一个一号进程也就是init进程所收养,而init进程会对这个孤儿进程进行善后工作,所以一般情况下我们不需要处理孤儿进程。
但是僵尸进程如果不处理会占用大量资源,所以我们必须要对僵尸进程进行处理,一般的处理方式我们有如下两种:
(1)用信号进行处理
信号处理是一般的做法,一般子进程退出的时候向父进程发送SIGCHILD信号,所以我们只需要捕捉这个信号,在信号处理函数中进行wait(),对其子进程进行善后工作,将不会产生僵尸进程。
(2)fork()两次进行处理
思路:
如果父进程处理时间长,子进程处理时间短,如果父进程不wait()处理的话,子进程就会产生僵尸进程,但是如果父进程进行了wait()处理,那么父进程又会产生阻塞,所以解决方法就是让自己尽快退出,任务让子进程的子进程来处理。
方法:
fork()两次的做法是在unix环境高级编程一书中所提到的,其方法是在fork第一次进程的里面再用一次fork,然后让第一次fork出来的子进程变为孤儿进程,交给init进程进行处理,自己则用waitpid善后即可。
三、僵尸进程与孤儿进程的实现
(一)孤儿进程
#include <unistd.h>#include <stdlib.h>#include <stdio.h>int main(){ pid_t pid = fork(); if (pid < 0) { perror("fork error"); exit(1); } //子进程 if (pid == 0) { printf("child\n"); printf("My Pid:%d,My Father pid:%d\n", getpid(), getppid()); //保证父进程退出 sleep(5); printf("My Pid:%d,My Father pid:%d\n", getpid(), getppid()); } else { printf("I am father\n"); sleep(1); printf("father exit!\n"); } return 0;}
(二)僵尸进程
提供了如下两种僵尸进程的方式:
①子进程退出,父进程不wait
#include <unistd.h>#include <stdlib.h>#include <stdio.h>int main(){ pid_t pid = fork(); if (pid < 0) { perror("fork error"); exit(1); } //子进程 if (pid == 0) { printf("child\n"); printf("My Pid:%d,My Father pid:%d\n", getpid(), getppid()); printf("I exit!\n"); exit(0); } printf("I am father\n"); //父进程等待1秒不处理子进程 sleep(1); //打印进程信息 system("ps -o pid,ppid,state,tty,command"); printf("father exit!\n"); return 0;}
四、僵尸进程与孤儿进程的解决方法实现
(1)用信号进行处理
#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <errno.h>#include <signal.h>static void sig_child(int signo);int main(){ pid_t pid; signal(SIGCHLD, sig_child); pid = fork(); if (pid < 0) { perror("Fork error"); exit(1); } if (pid == 0) { printf("I am child %d!\n", getpid()); exit(1); } printf("I an father! \n"); sleep(3); system("ps -o pid,ppid,state,tty,command"); printf("father exit!\n"); return 0;}static void sig_child(int signo){ pid_t pid; int stat; while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) printf("child %d terminated.\n", pid);}
(2)fork()两次进行处理
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>int main(){ pid_t pid = fork(); if (pid < 0) { perror("Fork error!\n"); exit(1); } if (pid == 0) { printf("The first pid:%d,ppid:%d\n", getpid(), getppid()); //此时fork第二次 pid = fork(); if (pid < 0) { perror("Fork error!\n"); exit(1); } else if (pid > 0) { //第一次创建的进程退出 printf("first exit!\n"); exit(0); } if (pid == 0) { //子进程休息三秒保证第一次fork出的进程退出,此时自己就变为孤儿进程了。 printf("I an second,pid:%d,ppid:%d\n", getpid(), getppid()); sleep(3); exit(0); } } //这里是处理第一个进程 if (waitpid(pid, NULL, 0) != pid) { perror("waitpid error!\n"); exit(1); } exit(0); return 0;}
- 僵尸进程与孤儿进程解析
- 解析僵尸进程与孤儿进程
- 僵尸进程与孤儿进程
- 僵尸进程与孤儿进程
- 僵尸进程与孤儿进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 僵尸进程与孤儿进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 孤儿进程与僵尸进程
- 使用STS工具创建Spring Boot或Spring MVC项目
- robotFramework之ExcelLibrary库
- 深度剖析:最新云端开发工具如何实现敏捷+DevOps开发落地
- Maven打包,把配置文件引用,打到外部
- 【头条】华为提“智慧城市神经系统”概念,背后有何新意?
- 解析僵尸进程与孤儿进程
- 负载均衡层次概念
- app的维护成本怎么算?
- 业余小项目——tzxblog博客系统
- 全志android编译过程
- Q群操作CPA自动赚钱、引流的秘诀与技巧
- TIM Ctrl + Shift + A 截图时 TIM的窗口被隐藏后才能开始截图
- 内核启动2-解决MBR学习分区
- 对象和封装