(1)忽略信号:即对信号不做任何处理,但是两个信号不能忽略:SIGKILL
以及SIGSTOP
.
(2)捕捉信号:当信号发生时,执行用户定义的信号处理函数。
(3)执行默认操作: Linux对每种信号都规定了默认操作,man 7 signal查看。
Term Default action is to terminate the process. Ign Default action is to ignore the signal. Core Default action is to terminate the process and dump core (see core(5)). Stop Default action is to stop the process. Cont Default action is to continue the process if it is currently stopped.
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }; /* sa_handler : 早期的捕捉函数 sa_sigaction : 新添加的捕捉函数,可以传参, 和sa_handler互斥,两者通过sa_flags选择采用哪种捕捉函数 sa_mask : 在执行捕捉函数时,设置阻塞其它信号,sa_mask | 进程阻塞信号集,退出捕捉函数后,还原回原有的 阻塞信号集 sa_flags : SA_SIGINFO 或者0用来指定调用sa_handler还是sa_sigaction,SA_SIGINFO时为调用sa_sigaction, SA_RESTART 让被打断的系统调用重新开始 sa_restorer : 保留,已过时 */
sigaction例子
void sig_handle(int sig) { puts("recv SIGINT"); sleep(5); puts("end"); } int main(int argc, char** argv) { struct sigaction act; act.sa_handler = sig_handle; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGQUIT); //当进入信号处理函数的时候,屏蔽掉SIGQUIT的递达 sigaction(SIGINT, &act, NULL); while(1) sleep(1); return 0; }
read函数的EINTR错误
信号能中断一些系统调用,返回-1并且设置errno为EINTR,例如read write sleep等,如果想要恢复这些函数继续运行可以加上 SA_RESTART标志。void sig_handle(int sig) { printf("SIGINT\n"); } int main(int argc, char** argv) { char buf[10]; struct sigaction act; act.sa_handler = sig_handle; act.sa_flags = 0; //act.sa_flags = SA_RESTART; //先试一试sa_flags为0时,然后再试一试SA_RESTART的情况 sigemptyset(&act.sa_mask); sigaction(SIGINT, &act, NULL); puts("read stdio:"); int ret = read(STDIN_FILENO, buf, 9); if(ret == -1) { if(errno == EINTR) perror("read:"); } else { buf[ret] = '\0'; printf("read %d : %s", ret, buf); } return 0; }
以上的运行结果的是,act.sa_flags = 0时一旦发送了一个信号,read将被打断,返回-1,并且设置errno为EINTR。如果想打断后继续运行read,可以设置一下act.sa_flags = SA_RESTART。或者也可以使用signal函数来处理信号,signal相当于默认设置了SA_RESTART标志。