// 如果信号对应的信号处理运行时间过长,其他的信号可能在信号处理程序尚未返回前达到,这将导致新到达的信号中断现有的信号处理程序的执行,或者新到达的信号
被忽略(如果调用signal(SIG_IGN)话)。但很多时候程序员希望新到达的信号不被忽略,并且是在现有信号处理程序返回后被处理,而不是中断现有的信号处理程序运行 。
解决方案sigaction 代替signal
相关API
//头文件: #include <signal.h>
//函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
// 功能: 注册信号关联的信号处理程序(用于代替signal).并能修改(或者获取)与指定信号关联的信号处理程序的行为参数。
//参数:
signum - 捕获的信号 。不能捕获SIGSTOP 或SIGKILL
act - 用于指定信号处理程序的行为参数
oldact - 用于保存信号处理程序的老行为参数。若不需要保存,则指定为NULL
// 返回值:
成功 返回 0 失败返回 -1
// struct sigaction 结构体讲解
// - struct sigaction {
void (*sa_handler)(int);
// 信号处理程序
void (*sa_sigaction)(int , siginfo_t * , void *);
// 指定信号处理程序。这个函数接收signum作为他的第一个参数,指向siginfo_t类型的指针作为第二个参数,
指向ucontext_t 作为第三个参数
sigset_t sa_mask;
//信号集合掩码 。该掩码中设置为1的位对应的信号将被屏蔽至信号处理程序结束后再被处理。默认情况下屏蔽同类信号
int sa_flags;
// 信号处理程序行为标志,其中较重要的有SA_SIGINFO 表示使用sa_sigaction代替sa_handler。SA_NODEFER表示不屏蔽同类信号
void (*sa_restorer)(void);
// 已废用
};
//信号处理程序行为标志
// - SA_NOCLDSTOP 若signum 是SIGCHLD ,当一子进程停止时,不产生此信号
// - SA_RESART 由此信号中断的系统调用自动重启
// - SA_ONSTACK 若用sigaltstack 已说明了一替换栈,则此信号提送给替换栈上的进程
// - SA_NOCLDWAIT 若signum 是SIGCHLD, 则当调用进程的子进程终止时,不创建僵尸进程。若调用进程在后面调用wait,则阻塞到他所有的子进程都终止,此时返回-1
// - SA_NODEFER 当扑捉到此信号时,在执行其信号捕获函数时,系统不自动阻塞此信号
// - SA_RESETHAND 对此信号的处理方式在此信号捕获函数的入口处恢复SIG_DFL
// - SA_SIGINFO 选此项对信号处理程序提供附加信号
eg:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void sig_int(int);
int main(int argc ,char *argv[]){
struct sigaction act;
sigset_t newmask ,oldmask ,pendmask;
if(signal(SIGQUIT , sig_int) == SIG_ERR){
printf("can't catch SIGQUIT");
exit(1);
}
if(signal(SIGINT , sig_int) == SIG_ERR){
printf("can't catch SIGINT");
exit(2);
}
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask , SIGQUIT);
act.sa_handler = sig_int;
act.sa_flags = 0 ;
if(sigaction(SIGINT , &act , NULL) == -1){
printf("can't catch SIGINT");
exit(3);
}
/* sigemptyset(&newmask);
sigaddset(&newmask , SIGQUIT);
if(sigprocmask(SIG_BLOCK , &newmask , &oldmask) < 0){
printf("SIG_BLOCK ERROR");
exit(4);
}
*/
sleep(15);
/* if(sigpending(&pendmask) < 0){
printf("sigpending error");
exit(5);
}
if(sigismember(&pendmask , SIGQUIT)){
printf("\nSIGQUIT pending \n");
}
if(sigprocmask(SIG_SETMASK , &oldmask , NULL) < 0){
printf("SIG_SETMASK error");
exit(6);
}
printf("SIGQUIT unblocked \n");
*/
sleep(100);
return 0;
}
static void sig_int(int signo){
int i ;
if(signo == SIGINT){
printf("received SIGINT \n");
for(i = 1000000000 ; i > 0 ; i--)
;
printf("processed SIGINT \n");
}else if(signo == SIGQUIT){
printf("caught SIGQUIT\n");
}else{
printf("received signal %d \n" , signo);
}
return ;
}