SIGCHLD信号
SIGCHLD的产生条件
子进程终止时
子进程接收到SIGSTOP信号停止时
子进程处在停止态,接受到SIGCONT后唤醒时
也就是说:子进程的运行状态发生变化就会发送SIGCHILD信号;这里的意思时,子进程比较依恋父母,自己发生变化就要给父母说一下。
借助SIGCHLD信号回收子进程
子进程结束运行,其父进程会收到SIGCHLD信号。该信号的默认处理动作是忽略。可以捕捉该信号,在捕捉函数中完成子进程状态的回收。不多说,上代码:
#include
				<stdlib.h>
#include
				<stdio.h>
#include
				<sys/types.h>
#include
				<sys/wait.h>
#include
				<unistd.h>
#include
				<signal.h>
void sys_err(char *p)
{
perror(p);
exit(1);
}
void do_sig_child(int
						signal)
{
printf("++++++++++++++++我是子进程,我的ID = %d\n", getpid());
}
void do_sig_parent(int
						signal)
{
int status;
while ((waitpid(0, &status, WNOHANG)>0))//如果清理成功
{
if (WIFEXITED(status))
{
printf("子进程正常退出,状态:%d\n", WEXITSTATUS(status));
}
        else
					if (WIFSIGNALED(status))
{
printf("———子进程异常退出,状态:%d\n", WTERMSIG(status));
}
}
}
int main(void)
{
int i = 0;
pid_t pid;
//屏蔽信号SIGCHLD
for (; i != 10; i++)
{
if (!(pid = fork()))
{
break;
}
        else
					if (pid<0)
{
sys_err("fork error ");
}
}
if (i<10)
{
do_sig_child(0);
sleep(1);//防止在父进程还未注册信号捕捉函数的时候子进程死亡。这样父进程就不能回收已死亡的子进程。
}
else
{
        struct
					sigaction act, oldact;
//修改信号处理动作
act.sa_handler = do_sig_parent;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGCHLD);
if ((sigaction(SIGCHLD, &act, &oldact))<0)
{
sys_err("sigaction error");
}
while (1)
{
printf("父进程的ID = %d\n", getpid());
sleep(1);
}
//还原信号处理动作
if ((sigaction(SIGCHLD, &oldact, &act))<0)
{
sys_err("sigaction error");
}
}
return 0;
}
现在,一切正常,运行结果:
现在我们来提问:如果每创建一个子进程后不使用sleep可以吗?可不可以将程序中,捕捉函数内部的while替换为if?为什么?
第一个问题我在代码中的注释已经写的很明白了,这里就不再说了。我们来说说另一个问题:捕捉函数do_sig_parent内部的while替换为if?为什么?即将代码 while((waitpid(0,&status,WNOHANG)>0))换为if((waitpid(0,&status,WNOHANG)>0))可以嘛?子进程一死亡就发送SIGCHLD信号给父进程,父进程收到后就执行捕捉函数。怎么不行呢?不管他行不行,我们试试就知道,实践出真知;结果如下: 这次还有一个子进程未回收,不行了,大野的,这个win10子系统太牛,同样的代码在别人的Linux系统上错误能够完美重现,在这里能够完美避开。我试了好几十次才找到这一个错误。但是没事,反正有了。
这次还有一个子进程未回收,不行了,大野的,这个win10子系统太牛,同样的代码在别人的Linux系统上错误能够完美重现,在这里能够完美避开。我试了好几十次才找到这一个错误。但是没事,反正有了。
来分析一下为啥if就不能完美的回收所有子进程:if只执行一次回收(因为到了那儿说明父进程收到信号了,也就是说一定有子进程死掉了。)但是若是某一个时刻有多个子进程同时死了,那么依据信号不进行排队的原理,就只有其中一个信号被处理。其他的被忽略。但是while就不一样了,就算同时来多个信号,但是while时循环执行,虽然信号处理先后顺序不一样,但是每个信号都会被处理啊(非阻塞的waitpid函数)。所以啊,当有多个子进程时,回收的时候用循环,不要用if。
SIGCHLD信号的更多相关文章
- unp TCP 客户端服务器回射程序中对SIGCHLD信号的处理
		第五章中,有一个例子模拟客户端并发的终止TCP连接,服务器捕捉并处理SIGCHLD信号并调用waitpid函数防止僵死进程的出现.信号处理函数中核心的一句是: , &statloc, WNOH ... 
- linux下的僵尸进程处理SIGCHLD信号
		什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该 ... 
- [转] linux下的僵尸进程处理SIGCHLD信号
		什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些 信息至少包括进程ID,进程的终止状态,以及 ... 
- 三十一、Linux 进程与信号——SIGCHLD 信号、kill和raise函数以及alarm函数
		31.1 SIGCHLD 信号 子进程状态发生变化(子进程结束)产生该信号,父进程需要使用 wait 调用来等待子进程结束并回收它. 避免僵尸进程 #include <stdio.h> # ... 
- linux下的僵尸进程处理SIGCHLD信号【转】
		转自:http://www.cnblogs.com/wuchanming/p/4020463.html 什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打 ... 
- 僵尸进程与SIGCHLD信号
		什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该 ... 
- 2次使用fork避免产生僵尸进程和不去处理SIGCHLD信号
		1.如下代码所示 #include <unistd.h> #include <sys/types.h> #include <unistd.h> int main(i ... 
- 僵进程与SIGCHLD信号
		参考: https://www.cnblogs.com/webor2006/p/4014586.html wait()和waitpid()的参数解析:https://blog.csdn.net/csd ... 
- linux有关信号的FAQ
		1.为什么会出现系统调用被中断的情况? 进程在执行一个低速系统调用而阻塞期间捕捉到一个信号时,该系统调用就被中断不再继续执行.该系统调用返回出错,其errno被设置为EINTR.这样处理的理由是:因为 ... 
随机推荐
- 996ICU的感悟
			并不只是口头上的支持,吉多·范罗苏姆近日又在 Python 官方论坛发布一篇名为<Can we do something for 996 programmers in China?>(我 ... 
- plsql怎么执行sql脚本
			首先,我们需要登录需要执行sql文件的用户,在我们确保sql文件无误的情况下,进入plsqldeveloper: 1,找到tools--->import tables --->选择sql ... 
- Python函数式编程-高阶函数、匿名函数、装饰器、偏函数
- 如何使用webpack打包项目
			webpack是前端开发中比较常用的打包工具之一,另外还有gulp,grunt.之前没有涉及过打包这块,这里介绍一下使用webpack打包的流程. Grunt和Gulp的工作方式是:在一个配置文件中, ... 
- Android---页面跳转
			1.首先在一个布局文件(.XML)中绘画了一个跳转按钮(id为btn1): <Button android:id="@+id/btn1" an ... 
- Java 10 - Java Character类
			Java Character类 使用字符时,我们通常使用的是内置数据类型char. 实例 char ch = 'a'; // Unicode for uppercase Greek omega cha ... 
- android:clipChildren属性,子布局超出父布局;
			是否允许子View超出父View的范围,Boolean型true .false ,默认true不允许: android:clipChildren="true":如下 android ... 
- 将任何GitHub内的代码转为外部CDN网址
			rawgit.com 有时候在GitHub找到需要使用于网站的档案(例如:CSS.JavaScript),但没有提供CDN网址就必须自己手动下载.上传到主机上才能够使用,有点耗时又不方便,因为GitH ... 
- rsyncd
			rsync是一个快速.通用的文件复制工具.支持两种工作模式:基于shell的传输.基于服务的传输.1.配置文件 rsyncd.conf文件由模块及其参数构成.模块由方括号包裹模块名称,直到下一个模块结 ... 
- 20165205 2017-2018-2 《Java程序设计》实验四 Android程序设计
			20165205 2017-2018-2 <Java程序设计>实验四 Android程序设计 实验内容 实验四 Android程序设计-1 Android Stuidio的安装测试: 参考 ... 
