转载请注明:http://www.coder4.com/index.php/archives/151
首先特别感谢这篇文章给的启发!
http://hi.baidu.com/%D3%EA%BA%E7%D1%F4/blog/item/6490202aaba49193023bf633.html
对原作者表示敬意和膜拜!
fork()之后,非阻塞(异步)等待子进程(回收僵尸)。
fork()之后,子进程和父进程分叉执行,僵尸进程的产生是因为父进程没有给子进程“收尸”造成的,又可以根据危害程度分为下述两类:
总体来说:当子进程结束之后,但父进程未结束之前,子进程将成为僵尸进程。
(1)当子进程结束之后,但父进程未结束之前,子进程将成为僵尸进程,父进程结束后僵尸被init进程回收。
(2)如果子进程结束了,但是父进程始终没有结束,那么这个僵尸将一直存在,而且随着exec,僵尸越来越多。
如下面的代码,在父进程执行的5s内,子进程将为僵尸:
/* * main.cc * * Created on: 2009-12-3 * Author: liheyuan * Describe: * * Last Date: 2009-12-3 * CopyRight: 2009 @ ICT LiHeyuan */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> int main() { //子进程的pid int c_pid; int pid; if ((pid = fork())) { //父进程 c_pid = pid; printf("The child process is %d\n", c_pid); sleep(5); exit(0); } else { //子进程 printf("I 'm a child.\n"); exit(0); } }
如上面的代码,在父进程的5s内,子进程一直是僵尸!
因此,需要对僵尸进程进行回收,传统的回收方法是,使用wait()函数,等待子进程,wait()是阻塞模式的,当子进程没有结束之前,wait一直等待,不往下面的语句执行。
/* * main.cc * * Created on: 2009-12-3 * Author: liheyuan * Describe: * * Last Date: 2009-12-3 * CopyRight: 2009 @ ICT LiHeyuan */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> int main() { //子进程的pid int c_pid; int pid; if ((pid = fork())) { //父进程 c_pid = pid; printf("The child process is %d\n", c_pid); //阻塞等待子进程 int status; if ((pid = wait(&status)) != -1 && pid == c_pid) { //成功回收子进程 printf("The child exit with %d\n", WEXITSTATUS(status)); fflush(stdin); } else { printf("wait() fail.\n"); } printf("Now , The child has been exit , and I will sleep.\n"); sleep(20); exit(0); } else { //子进程 printf("I 'm a child.\n"); sleep(5); exit(0); } }
如上面的代码,在子进程执行5秒后,即被回收,在夫进程的20秒内,子进程已经被结束,不再是僵尸。
但是这种利用wait()阻塞等待的方法也有一定的缺陷,那就是父进程必须等待子进程,无法做其他事情,如何非阻塞的等待子进程呢?
man wait,查看NOTES章节,可以找到:
子进程退出的时候,会发送SIGCHLD信号,默认的POSIX不响应,所以,我们只需要把处理SIGCHLD的函数自己实现就OK了,怎么作呢?
signal用于设置处理信号量的规则(或跳转到的函数)
signal(SIGCHLD,handler); void handler(int num) { //我接受到了SIGCHLD的信号啦 int status; int pid = waitpid(-1,&status,WNOHANG); if(WIFEXITED(status)) { printf("The child exit with code %d",WEXITSTATUS(status)); } }
OK,全部代码如下,注意父进程不要再用wait阻塞啦!
/* * main.cc * * Created on: 2009-12-3 * Author: liheyuan * Describe: * * Last Date: 2009-12-3 * CopyRight: 2009 @ ICT LiHeyuan */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> void handler(int num) { //我接受到了SIGCHLD的信号啦 int status; int pid = waitpid(-1, &status, WNOHANG); if (WIFEXITED(status)) { printf("The child %d exit with code %d\n", pid, WEXITSTATUS(status)); } } int main() { //子进程的pid int c_pid; int pid; signal(SIGCHLD, handler); if ((pid = fork())) { //父进程 c_pid = pid; printf("The child process is %d\n", c_pid); //父进程不用等待,做自己的事情吧~ for (int i = 0; i < 10; i++) { printf("Do parent things.\n"); sleep(1); } exit(0); } else { //子进程 printf("I 'm a child.\n"); sleep(2); exit(0); } }
转载请注明出处:http://www.coder4.com/index.php/archives/151