sigaction()函数可以设置各种属性在调用信号处理器程序时的行为,并且还允许在获取信号进行处理的同时不改变信号
1.头文件
#include <signal.h>
2.函数原型
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
3.参数
signum:参数指定需要捕获的信号
act:是指向 struct sigaction 的指针,用于设置新的信号处理方式,如果不需要这个参数,可以设置为NULL。
oldact:是指向 struct sigaction 的指针,用于存储原先的信号处理方式(可为 NULL 表示不需要保存旧的处理方式)。
4.返回值
成功返回0;失败返回-1,并设置 errno 以指示错误类型;
5.sigaction结构体定义
|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }; |
6.相关参数大致说明
sa_handler:信号处理函数,对应signal()函数的 handler 参数,可以使用SIG_DFL、SIG_IGN的定义,也可以指定信号处理函数的地址;只有sa_handler是信号处理函数的地址的时候,才会对后续的sa_mask、sa_flags进行处理。
sa_sigaction:扩展信号处理函数,比标准信号处理函数要复杂,注意不能同时使用sa_handler和sa_sigaction。sa_sigaction能够通过 siginfo_t类型的结构体指针和void类型的指针获得比标准信号处理函数更多的信息;
sa_mask:是定义的一组信号,在调用sa_handler的信号处理函数的时候,会阻塞这一组信号,防止信号处理函数执行过程中被另一个信号打断;同时当前正在处理的信号也会自动的加到进程信号掩码中,直到信号处理器函数结束并返回
sa_restorer:用以确保当信号处理器程序完成后,会去调用专用的sigreturn(),用来恢复进程之前所处的位置,让进程从信号处理器中断的位置继续执行;这个参数并不提供给用户的应用程序使用,不需要去配置这个;
sa_flags:是指定一系列用于修改信号处理过程行为的标志,由下面的0个或多个标志组合而成
⚫SA_NOCLDSTOP:如果signum是SIGCHLD,那么当子进程停止(即,当它们接收到SIGSTOP, SIGTSTP, SIGTTIN或SIGTTOU中的一个)或恢复(即,它们接收到SIGCONT)时,父进程不会接收到通知。这个标志只有在为SIGCHLD建立处理程序时才有意义。
⚫SA_NOCLDWAIT:如果signum是SIGCHLD,子进程终止的时候不会将其转化为僵尸进程。这个标志只有在为SIGCHLD建立处理程序时才有意义。
⚫SA_NODEFER:在捕获这个信号的时候,不会在执行处理器程序的时候将当前正在处理的这个信号自动添加到进程掩码里面,这个标志只有在建立信号处理程序时才有意义。
⚫SA_ONSTACK:调用由sigaltstack()提供的备用信号堆栈上的信号处理程序。如果替代堆栈不可用,则将使用默认堆栈。这个标志只有在建立信号处理程序时才有意义。
⚫SA_RESETHAND:在进入信号处理程序时将信号动作恢复为默认值。这个标志只有在建立信号处理程序时才有意义。SA_ONESHOT是该标志的过时的非标准同义词。
⚫SA_RESTART:自动重启由信号处理器程序中断的系统调用。
⚫SA_SIGINFO:信号处理程序接受三个参数,而不是一个。在这种情况下,就应该设置sa_sigaction而不是sa_handler处理程序。这个标志只有在建立信号处理程序时才有意义。
7.示例:通过sigaction()函数配置信号处理的行为
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> void signal_handler(int sig) { printf("this signal number is %d \n",sig); if (sig == SIGINT) { printf("get SIGINT!\n"); printf("The signal is restored to default processing!\n"); } } int main(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); /*清空屏蔽信号集*/ act.sa_flags = SA_RESETHAND; /*设置信号处理之后恢复默认的处理方式*/ sigaction(SIGINT, &act, NULL); while (1) { printf("waiting for signal...\n"); sleep(5); } exit(0); } |
8.运行结果
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| waiting for signal... waiting for signal... ^Cthis signal number is 2 get SIGINT! The signal is restored to default processing! waiting for signal... waiting for signal... ^C |
9.代码解析
通过配置sigaction的结构体act用于指定信号处理的行为,定义signal_handler为信号处理函数,接收到指定信号的时候调用它进行处理;然后初始化信号集为空,不阻塞任何信号;并且配置标志为处理之后恢复到默认处理方式的标志,这样就可以不用在处理函数里面再配置恢复了,这也意味着信号处理函数只会执行一次;最后让sigaction函数注册信号处理器,使用act中定义的处理方式;main()中进入无限循环等待,不过信号的通信方式是异步的,所以并不受影响。直接执行程序,第一次按CTRL+C收到SIGINT信号会打印相关信息,处理结束之后将信号的处理方式恢复默认,再一次按CTRL+C就能正常退出进程。