遇到信号量的问题?
signal(SIGCLD,SIG_IGN)
SIGCHLD的语义为:子进程状态改变后产生此信号,父进程需要调用一个wait函数以确定发生了什么。
对于SIGCLD的早期处理方式如下:如果进程特地设置该信号的配置为SIG_IGN,则调用进程的子进程将不产生僵死进程。
如果将SIGCLD的配置设置为捕捉,则内核立即检查是否有子进程准备好被等待,如果是这样,则调用SIGCLD处理程序。
APUE上SIGCLD语义写的有点不清楚,到底我们的系统是如何来处理SIGCLD信号呢?
1.SIG_DFL :默认的处理方式是不理会这个信号,但是也不会丢弃子进行状态,所以如果不用wait,waitpid
有朋友疑惑“为什么有了wait函数族还需要使用SIGCHLD信号?”。本文详细地阐述UNIX系统中wait函数族和SIGCHLD信号的关系。
一、unix中僵尸进程的含义
关于unix中僵尸进程的含义:
凡是父进程没有调用wait函数获得子进程终止状态的子进程在终止之后都是僵尸进程,这个概念的关键一点就是父进程是否调用了wait函数。
二、SIGCHLD信号
SIGCHLD信号的含义:
简单的说,子进程退出时父进程会收到一个SIGCHLD信号,默认的处理是忽略这个信号,而常规的做法是在这个信号处理函数中调用wait函数获取子进程的退出状态。
三、既然在SIGCHLD信号的处理函数中要调用wait函数族,为什么有了wait函数族还需要使用SIGCHLD信号?
我们知道,unix中信号是采用异步处理某事的机制,好比说你准备去做某事,去之前跟邻居张三说如果李四来找你的话就通知他一声,这让你可以抽身出来去做这件事,而李四真正来访时会有人通知你,这个就是异步信号一个较为形象的比喻。
一般的,父进程在生成子进程之后会有两种情况:一是父进程继续去做别的事情,类似上面举的例子;另一是父进程啥都不做,一直在wait子进程退出。
SIGCHLD信号就是为这第一种情况准备的,它让父进程去做别的事情,而只要父进程注册了处理该信号的函数,在子进程退出时就会调用该函数,在函数中wait子进程得到终止状态之后再继续做父进程的事情。
最后,我们来明确以下二点:
1)凡父进程不调用wait函数族获得子进程终止状态的子进程在退出时都会变成僵尸进程。
2)SIGCHLD信号可以异步的通知父进程有子进程退出。
四、僵尸进程有啥危害
所谓僵尸进程,形象来说,进程已死,但其尸体还在,没人收尸啊,冤魂不散,仍然占用一个进程号,如果主进程不妥善处理,当僵尸进程数量巨大之后,就没法再次fork了,所以对于大型并发服务器来说,当建立了进程池,一定要想办法处理掉所有僵尸进程。
# include
# include
# include
# include
# include
void sigchld_handler( int signo ){
printf("sigchld_handler\n");
sleep(3);
return;
}
int main()
{
int i;
pid_t pid;
pid_t cpid;
signal( SIGCHLD, sigchld_handler );
for( i=0; i<5; i++ ){
pid = fork();
if ( pid == 0 ){
sleep(2);
exit(0); // child exit.
}
else if ( pid == -1 ){
perror( "fork" ); // fork failed.
exit(-1);
}
}
printf("before wait\n");
system( "ps -ef | grep ttt" );
// while((cpid = waitpid(-1,NULL,0)!=-1)) {
while ((cpid = wait(NULL)) != -1) {
printf("wait pid is %d\n", cpid);
continue;
}
printf("after wait\n");
system( "ps -ef | grep ttt" );
}
./ttt
before wait
root 3094 2800 0 18:29 pts/0 00:00:00 ./ttt
root 3095 3094 0 18:29 pts/0 00:00:00 ./ttt
root 3096 3094 0 18:29 pts/0 00:00:00 ./ttt
root 3097 3094 0 18:29 pts/0 00:00:00 ./ttt
root 3098 3094 0 18:29 pts/0 00:00:00 ./ttt
root 3099 3094 0 18:29 pts/0 00:00:00 ./ttt
root 3100 3094 0 18:29 pts/0 00:00:00 sh -c ps -ef | grep ttt
root 3102 3100 0 18:29 pts/0 00:00:00 grep ttt
sigchld_handler
sigchld_handler
wait pid is 3095
wait pid is 3096
wait pid is 3097
wait pid is 3098
wait pid is 3099
after wait
root 3094 2800 0 18:29 pts/0 00:00:00 ./ttt
root 3103 3094 0 18:29 pts/0 00:00:00 sh -c ps -ef | grep ttt
root 3105 3103 0 18:29 pts/0 00:00:00 grep ttt
sigchld_handler
这是一个sig和wait联合处理到例子(当然通常做法有2种,1是在sig 处理函数中调用wait处理,2是不要sig 处理函数,单独调用wait处理)。但是程序结果,让人很意外,为什么当产生SIGCHLD信号时,wait阻塞没有被中断,而是处理正常,所有子进程都正确退出,没有产生僵尸进程呢。按理说。wait阻塞时,当产生SIGCHLD信号,应该中断,同时返回-1,error no为EINTR,