fork子进程僵尸问题及解决方案
额,原来用 c 写 cgi 的时候用过 fork 。那时候 cgi 的生命很短,所以遇到的问题压根没出现过。这次也是更加深入的对 fork 机制进行了一下了解。
参考这里的文档:http://ju.outofmemory.cn/entry/98971
1. 我们都是小僵尸
下面是这次应用的一个 fork 的例子。主进程继续进行数据处理,一定时间后用下面的代码开新进程,并将处理结果发送出去。看起来似乎没什么问题,但是,一定时间后,fork 总是failed。。。用 ps aux 查看进程列表,列表被僵尸进程占满了!!
...
if ((pid=fork())<)
{
printf("fork failed \n");
}
else if ( == pid)
{
test_result.error_1 = (double)error_1 / test_result.total * ;
test_result.error_2 = (double)error_2 / test_result.total * ;
test_result.error_4 = (double)error_4 / test_result.total * ;
test_result.error_6 = (double)error_6 / test_result.total * ; n = sendto(sock, &test_result, sizeof(test_result), ,
(struct sockaddr *)&addr_to, sizeof(addr_to));
exit();
}
...
好吧,难道 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(-, NULL, WNOHANG)) > ) {
printf("SIGCHLD pid %d\n", pid);
}
}
}
void mysleep(int sec) {
time_t start = time(NULL), elapsed = ;
while (elapsed < sec) {
sleep(sec - elapsed);
elapsed = time(NULL) - start;
}
}
int main(int argc, char **argv) {
signal(SIGCHLD, signal_handler);
while () {
pid_t pid = fork();
if (pid > ) {
// parent process
mysleep();
} else if (pid == ) {
// child process
printf("child pid %d\n", getpid());
return ;
} else {
fprintf(stderr, "fork error\n");
return ;
}
}
}
比如上面的代码。我们在信号处理中使用了一个循环体,不断调用waitpid(),直到失败为止。那是因为在系统繁忙时,信号可能会被合并,即两个子进程结束只会发送一次SIGCHLD信号,如果只wait()一次,就会产生僵尸进程。(由于默认的sleep()函数会在接收到信号时立即返回,因此为了方便演示,这里定义了mysleep()函数)。
4.做个不负责任的爸爸
很简单,用下面这句话,告诉操作系统,你不关心所有那些子进程的死活。
signal(SIGCHLD, SIG_IGN);
但是,这样做的问题是,有些BSD系统不支持这样的用法。所以,更为广泛的,还是使用wait。
perl中
下面是perl中使用fork-waitpid的代码,也是也不是我写的:
#!/usr/bin/perl
sub REAPER {
my $pid;
while (($pid = waitpid(-, WNOHANG)) > ) {
print "SIGCHLD pid $pid\n";
}
}
$SIG{CHLD} = \&REAPER;
my $pid = fork();
if ($pid > ) {
print "[Parent] child pid $pid\n";
sleep();
} elsif ($pid == ) {
print "[Child] pid $$\n";
exit;
}
这个和c基本一样的。如果想要忽略SIGCHLD,可使用$SIG{CHLD} = 'IGNORE'。
fork子进程僵尸问题及解决方案的更多相关文章
- fork子进程
title: fork子进程 data: 2019/3/21 20:24:39 toc: true --- 这里实在学习socket编程前的小知识点,用来创建多个服务端 学习文档 函数可以有两个返回值 ...
- fork()和僵尸进程
2018-01-03@望京 关于fork()函数,Unix/Linux提供的fork()系统调用,fork()一次返回两次, 操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在 ...
- 缺陷的背后(四)---多进程之for循环下fork子进程引发bug
导语 业务模块为实现高并发时的更快的处理速度,经常会采用多进程的方式去处理业务.多进程模式下常见的三种bug:for循环下fork子进程导致产生无数孙子进程,僵尸进程,接口窜包.本章主要介绍第一种常见 ...
- localtime死锁——多线程下fork子进程
近期測试我们自己改进的redis,发如今做rdb时,子进程会一直hang住.gdb attach上.堆栈例如以下: (gdb) bt #0 0x0000003f6d4f805e in __lll_lo ...
- 转:fork()子进程创建
源地址:http://blog.chinaunix.net/uid-23037385-id-2565472.html fork()子进程创建 在 UNIX 系统中,用户创建一个新进程的唯一方法就是调用 ...
- 故障:fork failed:Resource Temporarily Unavailable解决方案
故障:fork failed:Resource Temporarily Unavailable解决方案 AIX在一次crontab bkapp.txt导入N多定时任务时候,该用户无法执行任何命令,再s ...
- 异步回收fork出的子进程(僵尸进程)
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h&g ...
- !!!!Linux系统开发 系列 4 进程资源 环境 fork()子进程 wait() waitpid()僵尸 孤儿进程
http://990487026.blog.51cto.com/10133282/1834893
- fork和僵尸进程
1. 关于fork fork()函数: 用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息:在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行 ...
随机推荐
- Linux execve函数簇用法
exec函数簇实现的功能都是用一个新程序替换原来的程序,替换的内容包括堆栈段,代码段,进程控制器PCD,但是原进程的PID保持不变 int execl(const char *path, const ...
- jboss EAP 6.2+ 通过代码控制JNDI数据源
通过Jboss提供的API,可以操控JBoss,效果跟在管理控制台手动操作完全一样,下面是示例代码: 一.pom.xml添加依赖项 <dependency> <groupId> ...
- 解决 未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”中加载
先安装了 IIS ,再安装了 .net framework4.0 ,这样一来就要在cmd下注册.net framework4.0 步骤 第一步:修改配置文件 %windir%/system32/ine ...
- Java:泛型
一.序言 变化一: 在引入范型之前,Java中的类型分为原始类型.复杂类型,其中复杂类型分为数组和类:引入范型后,一个复杂类型可以细分成更多的类型. 例如,原先的List类型,现在细分成List< ...
- APP架子迁移指南(二)
接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...
- retrofit2中ssl的Trust anchor for certification path not found问题
在retrofit2中使用ssl,刚刚接触,很可能会出现如下错误. java.security.cert.CertPathValidatorException: Trust anchor for ce ...
- 用 Linux自带的logrotate 来管理日志
大家可能都有管理日志的需要,比如定时压缩日志,或者当日志超过一定大小时就自动分裂成两个文件等.最近就接到这样一个小任务.我们的程序用的是C语言,用log4cpp的library来实现日志记录.但是问题 ...
- js的Object和Function
自己闲的没事干,自己想通过js的了解写一个Function和Object之间的关系,可以肯定的是我写错了,但是希望可以有所启发. Function和Object Function.__proto__ ...
- 在eclipse中使用第三方库总结
一.建立user library 导入第三方jar文件,最简单的方式是:右键工程/属性/java build path/add external jars. 另一种方式是:window/prefren ...
- SharePoint 站点集和子站点数据互相读取
1.站点集中可以使用SPSite.AllWeb,然后遍历所有站点的isRootWeb,根据siteTemplate取得需要的子站点. /// <summary> /// Handles t ...