解析僵尸进程与孤儿进程
2017-11-29 21:07
369 查看
一、僵尸进程与孤儿进程的定义
我们知道一个子进程如果要结束,其内核释放进程的所有资源,但是还保存了一部分资源供父进程使用(是一个被称之为僵尸进程的数据结构,包含有进程号、运行时间、退出状态等,它需要父进程去处理),所以其父进程要调用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; }
相关文章推荐
- 浅析三种特殊进程:孤儿进程,僵尸进程和守护进程.
- 孤儿进程与僵尸进程
- 僵尸、孤儿、守护进程
- Linux下僵尸进程与孤儿进程
- 进程概念之孤儿与僵尸
- 僵尸进程和孤儿进程的区别
- 浅谈三种特殊进程:孤儿进程,僵尸进程和守护进程
- 僵尸进程和孤儿进程
- 浅析三种特殊进程:孤儿进程,僵尸进程和守护进程.
- APUE 读书笔记 -----孤儿进程与僵尸进程[总结] +数据结构+C
- 孤儿进程和僵尸进程
- 孤儿进程与僵尸进程[总结]
- 僵尸进程,孤儿进程是如何产生
- Linux — 孤儿进程和僵尸进程
- PHP实现系统编程(二) --- 多进程编程介绍及孤儿进程、僵尸进程
- 僵尸进程和孤儿进程
- 进程与线程(三) 孤儿进程与僵尸进程
- 僵尸进程和孤儿进程
- 孤儿进程与僵尸进程[总结]
- 僵尸进程和孤儿进程