接着上面的内容写,每个信号都有相关联的默认行为,信号的默认行为可以改变,但是SIGSTOP和SIGKILL不可以,要是都可以估计会对系统有害,尤其是入侵或者搞破坏的人会
也是为了系统的安全性着想吧,signal的第二个参数可以决定忽略,默认,使用中断函数这三种应对信号的方式。
信号处理问题:对于只捕获一个信号就终止的程序来说信号的处理非常简单,捕获多个的时候就产生细微的问题了。
1.待处理信号被阻塞:linux信号处理程序会阻塞当前处理程序正在处理的类型的待处理信号,比如正在处理一个SIGINT触发的函数,过程中又来了一个SIGINT函数,那么这个SIG
INT将变成待处理的信号了,但是不会接收,直道程序返回。
2.待处理信号不会排队等待:任意类型的信号至多有一个待处理信号。
3.系统调用可以被中断。read,write这类函数会潜在的阻塞进程一段较长时间,成为慢速系统调用,当处理程序捕获一个信号的时候,被中断的慢速系统调用在信号处理程序返回时不再继续,而是返回给用户一个错误条件,并且将errno设置为EINTR
案例代码:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<wait.h>
#include<errno.h>
#include<signal.h>
pid_t Fork(void)
{
pid_t pid;
if((pid=fork())<0)
{
perror("Fork error");
}
return pid;
}
void handler(int sig)
{
pid_t pid;
if((pid=waitpid(-1,NULL,0))<0)
{
printf("waitpid error");
}
printf("Handler reaped child %d\n",(int)pid);
sleep(2);
return;
}
int main()
{
int i,n;
char buf[255];
//只要有一个子进程终止或者停止内核就发送SIGCHLD信号给父进程
if(signal(SIGCHLD,handler)==SIG_ERR)
{
printf("signal error");
}
for(i=0;i<3;i++)
{
if(Fork()==0)
{
//创建三个子进程,并且休眠1秒后退出
printf("Hello from child %d\n",(int)getpid());
sleep(1);
exit(0);
}
}
//父进程等待来自终端的一个输入行。当每个子进程终止时,父进程
//根据信号处理子进程回收工作,并且可以处理一些其他的事情想sleep(2) handler函数
if((n=read(STDIN_FILENO,buf,sizeof(buf)))<0)
{
//从输入缓冲区读数据到数组buf
printf("read error");
}
printf("Parent processing input\n");
while(1)
;
exit(0);
}
结果并不理想,创建了三个子进程却只回收了两个!关键在于代码没有解决信号可以阻塞和不会排队等待这样的情况。发生的情况是当处理程序还在处理第一个信号的时候第二个信号就添加到了待处理的信号的集合里面,然而因为SIGCHLD被SIGCHLD处理程序阻塞了,第二个信号不会接受,此后不久,第三个信号到来了,因为已经有一个SIGCHLD等待处理,第三个会被丢弃。一段时间后,处理程序完事了,内核发现还有一个待处理的SIGCHLD信号,就迫使父进程不要回到main函数,就直接执行这个信号的处理函数了,所以第二次执行处理函数,处理完后,因为第三个已经被丢弃了,所以以后也不会有中断信号产生了。就这样。。。
所以不可以用信号对其他进程中发生的事件计数
注:linux系统会自动重启被中断的系统调用。
void handler2(int sig)
{
pid_t pid;
while((pid=waitpid(-1,NULL,0))>0)
{
printf("Handler reaped child %d\n",(int)pid);
}
if(errno !=ECHILD)
{
print("waitpid error");
}
sleep(2);
return;
}
上面这段代码解决了上面的问题。