10.7 SIGCLD semantics
SIGCLD是在system v的系列版本中使用的一个信号。SIGCHLD是BSD系列版本中使用的信号,他们的意义有所不同,其中SIGCLD应该被禁用。其原因如下:
(一) system 的SIGCLD
SVR4是从system v发展出来的,它使用SIGCLD的方法(如下都以signal和sigset函数作为signal安装函数) :
1.被推荐的使用SIGCLD的方法
设置SIGCLD为SIG_IGN,这样生成的孩子process在退出后不会生成zombia。
2.不被推荐的使用方法
就是默认的对SIGCLD的处理方法,即SIG_DFL,子进程结束后不处理,如果父亲wait的话,会等所有的孩子进程结束后才返回-1,errno=ECHLD。这不是推荐的。
可见在System v系列里,对SIGCLD的使用推荐使用SIG_IGN。
3.system v的SIGCLD的一个被诟病的地方
就是当用signal安装SIGCLD的handler的时候,他会立马检查当前是否有孩子进程可以被waited,如果有,就立马调用handler。这会造成stack overflow,例如:我们用signal安装handler的时候,经常在signal handler里面首先将handler reinstall, 好,当有一个子进程结束了,发送了SIGCLD信号,该handler被调用,reinstall 该handler, 立马检查是否有可以waited的进程,有,立马调用handler, ….如此循环,不久死掉了么.
如下就是例子代码:
Figure 10.6. System V SIGCLD handler that doesn't work
#include "apue.h"
#include <sys/wait.h>
static void sig_cld(int);
int
main()
{
pid_t pid;
if (signal(SIGCLD, sig_cld) == SIG_ERR)
perror("signal error");
if ((pid = fork()) < 0) {
perror("fork error");
} else if (pid == 0) { /* child */
sleep(2);
_exit(0);
}
pause(); /* parent */
exit(0);
}
static void
sig_cld(int signo) /* interrupts pause() */
{
pid_t pid;
int status;
printf("SIGCLD received\n");
if (signal(SIGCLD, sig_cld) == SIG_ERR) /* reestablish handler */
perror("signal error");
if ((pid = wait(&status)) < 0) /* fetch child status */
perror("wait error");
printf("pid = %d\n", pid);
}
可见system v系列不能给SIGCLD安装handler,那么就只能采用推荐的方法SIG_IGN了。使其子进程压根不产生zombia.
(二)SIGCHLD
在linux里,用signal安装SIGCHLD,且将handler置为SIG_IGN,也会达到是子进程退出后不产生zombia的好处。而默认的我们不处理该信号,就会产生zombia。BSD系列就是这样。
如下是摘自linux suse man page的一段话:
POSIX.1-1990 disallowed setting the action for SIGCHLD to SIG_IGN. POSIX.1-2001 allows this possibility, so that ignoring SIGCHLD can be used to prevent the creation of zombies (see wait(2)). Nevertheless, the historical BSD and System V behaviors for ignoring SIGCHLD differ, so that the only completely portable method of ensuring that terminated children do not become zombies is to catch the SIGCHLD signal and perform a wait(2) or similar.
鉴于不同平台的对SIGCHLD的设置成SIG_IGN的意义的不同,唯一的更portable的避免zombia的方法是在SIGCHLD的handler里面调用wait。
(三)使不产生zombia孩子的另一个方法
使用sigaction并设置SA_NOCLDWAIT标记。
(四)在包括linux在内的一些平台,SIGCLD被宏定为SIGCHLD,放心使用