fork子进程僵尸问题及解决方案
来源:互联网 发布:淘宝客网站推广 编辑:程序博客网 时间:2024/06/05 02:01
转自:http://www.cnblogs.com/pied/p/4441734.html
原来用 c 写 cgi 的时候用过 fork 。那时候 cgi 的生命很短,所以遇到的问题压根没出现过。这次也是更加深入的对 fork 机制进行了一下了解。
参考这里的文档:http://ju.outofmemory.cn/entry/98971
1. 我们都是小僵尸
下面是这次应用的一个 fork 的例子。主进程继续进行数据处理,一定时间后用下面的代码开新进程,并将处理结果发送出去。看起来似乎没什么问题,但是,一定时间后,fork 总是failed。。。用 ps aux 查看进程列表,列表被僵尸进程占满了!!
... if ((pid=fork())<0) { printf("fork failed \n"); } else if ( 0 == pid) { test_result.error_1 = (double)error_1 / test_result.total * 10000; test_result.error_2 = (double)error_2 / test_result.total * 10000; test_result.error_4 = (double)error_4 / test_result.total * 10000; test_result.error_6 = (double)error_6 / test_result.total * 10000; n = sendto(sock, &test_result, sizeof(test_result), 0, (struct sockaddr *)&addr_to, sizeof(addr_to)); exit(0); }...
好吧,难道 exit(0) 之后,它还在留恋什么?所以,又回来继续摸索什么是最有可能性。
2. 小僵尸找爸爸
好吧,最后目光落到了这里 SIGCHLD。通常,父进程不会始终处于等待状态,它还需要执行其它代码,因此“等待”的工作会使用信号机制来完成;或者说,子进程在处理完任务以后,内核会发送一个SIGCHLD信号。。。对,这孩子还要向它爸做最后的告别。
那孩它爸能做些什么呢?
1)孩它爸也不在了。
2)孩它爸在等待关于这孩子的消息,完成告别仪式,各安天命。
3)孩它爸发布了告示“我没有儿子,你们都别来烦我”。
恩,第一个这是肯定的,因为fork机制天生的属性,如果孩它爸不在了,它会被送给init来监管抚养。。。init是个负责任的好爸爸,他会处理好一切。那接下来两个是怎么回事呢?
3.小僵尸和爸爸最后的告别
用于监督子进程的完成情况,fork配套使用的有waitpid()和wait()两个函数。waitpid()的功能和wait()类似,但waitpid()提供了额外的选项(wait(NULL)等价于waitpid(-1, NULL, 0))。如,wait()函数是阻塞的,而waitpid()提供了WNOHANG选项,调用后会立刻返回,可根据返回值判断等待结果。
#include <stdint.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include <malloc.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>void signal_handler(int signo) { if (signo == SIGCHLD) { pid_t pid; while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { printf("SIGCHLD pid %d\n", pid); } }}void mysleep(int sec) { time_t start = time(NULL), elapsed = 0; while (elapsed < sec) { sleep(sec - elapsed); elapsed = time(NULL) - start; }}int main(int argc, char **argv) { signal(SIGCHLD, signal_handler); while (1) { pid_t pid = fork(); if (pid > 0) { // parent process mysleep(5); } else if (pid == 0) { // child process printf("child pid %d\n", getpid()); return 0; } else { fprintf(stderr, "fork error\n"); return 2; } }}
比如上面的代码。我们在信号处理中使用了一个循环体,不断调用waitpid(),直到失败为止。那是因为在系统繁忙时,信号可能会被合并,即两个子进程结束只会发送一次SIGCHLD信号,如果只wait()一次,就会产生僵尸进程。(由于默认的sleep()函数会在接收到信号时立即返回,因此为了方便演示,这里定义了mysleep()函数)。
4.做个不负责任的爸爸
很简单,用下面这句话,告诉操作系统,你不关心所有那些子进程的死活。
signal(SIGCHLD, SIG_IGN);
但是,这样做的问题是,有些BSD系统不支持这样的用法。所以,更为广泛的,还是使用wait。
perl中
下面是perl中使用fork-waitpid的代码,也是也不是我写的:
#!/usr/bin/perlsub REAPER { my $pid; while (($pid = waitpid(-1, WNOHANG)) > 0) { print "SIGCHLD pid $pid\n"; }}$SIG{CHLD} = \&REAPER;my $pid = fork();if ($pid > 0) { print "[Parent] child pid $pid\n"; sleep(10);} elsif ($pid == 0) { print "[Child] pid $$\n"; exit;}
这个和c基本一样的。如果想要忽略SIGCHLD,可使用$SIG{CHLD} = 'IGNORE'。
- fork子进程僵尸问题及解决方案
- 异步回收fork出的子进程(僵尸进程)
- 异步回收fork出的子进程(僵尸进程)
- 异步回收fork出的子进程(僵尸进程)
- 异步回收fork出的子进程(僵尸进程)
- 异步回收fork出的子进程(僵尸进程)
- 异步回收fork出的子进程(僵尸进程)
- fork() 与僵尸进程
- APUE之fork两次与僵尸进程的问题
- fork和defunct(僵尸)进程
- 两次fork防止僵尸进程
- fork两次解决僵尸进程
- fork产生僵死子进程的问题
- 子进程等待父进程退出及fork使用
- 进程管理:fork与exec函数及fork子进程和父进程
- linux子进程fork
- fork子进程缓冲
- fork创建子进程
- sec_db一期落幕总结
- Extjs怎样隐藏按钮
- 速度传感器
- 关于全局变量,如何被多个.c文件共享问题
- 当遇到老版本的java代码与新代码不一样时怎么办
- fork子进程僵尸问题及解决方案
- 响应式图像--图片自适应大小
- 设计模式-001策略模式
- 第2周项目1-C/C++语言中函数参数传递的三种方式
- 加速传感器
- android中fragment之间传值
- JAVA中几种数据填写后提交按钮改变状态
- 懒出效率
- mustache.js官网教程