码迷,mamicode.com
首页 > 其他好文 > 详细

SIGCHLD 信号处理

时间:2015-04-03 00:22:33      阅读:354      评论:0      收藏:0      [点我收藏+]

标签:

linux下进程终止时,内核会向父进程发送一个SIGCHLD信号,其有几个特点:

1.在一个信号处理函数运行期间,正被递交的信号是阻塞的。

2.如果一个信号在被阻塞期间产生了一次或多次,那么该信号被解阻塞之后通常只递交一次,也就是说linux信号默认是不排队的。

举个栗子:

进程的第一个子进程终止产生信号(1),(1)信号处理过程中第二个子进程终止产生信号(2),此时(1)处于正在处理状态,(2)处于等待处理状态,接着又有第三、四、五子进程终止产生信号(3)(4)(5);(1)信号处理函数执行完后,只进行(2)信号的处理,其余信号(3)(4)(5)则丢失。

编写linux多进程的并发服务程序时,我们需要处理客户端退出,服务端fork出的子进程变为僵死(zombie)进程的情况,通常这样来做:

signal(SIGCHLD, sig_chld);
void sig_chld(int signo)
{
    pid_t   pid;
    int     stat;
    while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) {
        printf("child %d terminated\n", pid);
    }
    return;
}

这里我们指定WNOHANG选项,它告知waitpid在有尚未终止的子进程在运行时不要阻塞。我们不能在循环中调用wait,因为没有办法防止wait在正在运行的子进程尚有未终止时阻塞。另外值得注意的是,在信号处理函数中使用printf等不可重入函数是不推荐的。

查看waitpid的man手册,有这样一段描述:

POSIX.1-2001  specifies that if the disposition of SIGCHLD is set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD (see sigaction(2)), then children that terminate do not become zombies and a call to wait() or waitpid() will block until all children have terminated, and then fail with errno set to ECHILD.  

提供了另外两种僵死进程处理的办法:signal(SIGCHLD, SIG_IGN); 或为SIGCHLD设置SA_NOCLDWAIT标志。

上述方法,在高并发场景下仍存在缺陷,SIGCHLD信号在上面代码的作用,其实只是通知进行waitpid调用,waitpid循环处理所有已经终止的子进程。假设一种情况,服务端支持最大2k的并发,满负载时2k个客户端同时退出,按上面例子会有大量信号丢失,产生的僵死进程在下次父进程收到SIGCHLD信号时得到清理,此时服务端只能提供少量并发请求(最坏情况2个并发);

简短描述一下该问题:高并发下,上述代码的waitpid在清理僵死进程时不及时。

一种解决办法是我们自己来维护子进程的退出状态。创建一个队列,子进程退出时将pid入队列,在线程中阻塞读并处理队列。


SIGCHLD 信号处理

标签:

原文地址:http://my.oschina.net/zangzy/blog/395434

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!