linux的信号捕捉函数详解
信号捕捉
signal函数
注册一个信号捕捉函数:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
该函数由ANSI定义,由于历史原因在不同版本的Unix和不同版本的Linux中可能有不同的行为。因此应该尽量避免使用它,取而代之使用sigaction函数。
void (*signal(int signum, void (*sighandler_t)(int))) (int);
能看出这个函数代表什么意思吗? 注意多在复杂结构中使用typedef。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <signal.h> void do_sig(int a) { printf("Hi, SIGINT, how do you do ! "); } int main(void) { if (signal(SIGINT, do_sig) == SIG_ERR) { perror("signal"); exit(1); } while (1) { printf("--------------------- "); sleep(1); } return 0; }
#include <signal.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> typedef void (*sighandler_t) (int); void catchsigint(int signo) { printf("-----------------catch "); } int main(void) { sighandler_t handler; handler = signal(SIGINT, catchsigint); if (handler == SIG_ERR) { perror("signal error"); exit(1); } while (1); return 0; }
sigaction函数
修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 成功:0;失败:-1,设置errno
参数:
act:传入参数,新的处理方式。
oldact:传出参数,旧的处理方式。 【signal.c】
struct 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);
};
sa_restorer:该元素是过时的,不应该使用,POSIX.1标准将不指定该元素。(弃用)
sa_sigaction:当sa_flags被指定为SA_SIGINFO标志时,使用该信号处理程序。(很少使用)
重点掌握:
① sa_handler:指定信号捕捉后的处理函数名(即注册函数)。也可赋值为SIG_IGN表忽略 或 SIG_DFL表执行默认动作
② sa_mask: 调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。
③ sa_flags:通常设置为0,表使用默认属性。
信号捕捉特性
1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为☆。
2. XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
练习1:为某个信号设置捕捉函数 【sigaction1.c】
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> /*自定义的信号捕捉函数*/ void sig_int(int signo) { printf("catch signal SIGINT ");//单次打印 sleep(10); printf("----slept 10 s "); } int main(void) { struct sigaction act; act.sa_handler = sig_int; act.sa_flags = 0; sigemptyset(&act.sa_mask); //不屏蔽任何信号 sigaddset(&act.sa_mask, SIGQUIT); sigaction(SIGINT, &act, NULL); printf("------------main slept 10 "); sleep(10); while(1);//该循环只是为了保证有足够的时间来测试函数特性 return 0; }
练习2: 验证在信号处理函数执行期间,该信号多次递送,那么只在处理函数之行结束后,处理一次。 【sigaction2.c】
/*自动屏蔽本信号,调用完毕后屏蔽自动解除*/ #include <stdio.h> #include <signal.h> #include <unistd.h> /*自定义的信号捕捉函数*/ void sig_int(int signo) { printf("catch signal SIGINT "); sleep(10); //模拟信号处理函数执行很长时间 printf("end of handler "); } int main(void) { struct sigaction act, old; act.sa_handler = sig_int; sigemptyset(&act.sa_mask); //依然不屏蔽任何信号 act.sa_flags = 0; sigaction(SIGINT, &act, &old); //注册信号处理函数 while(1); sigaction(SIGINT, &old, NULL); //注册信号处理函数 return 0; }
练习3:验证sa_mask在捕捉函数执行期间的屏蔽作用。 【sigaction3.c】
/*当执行SIGINT信号处理函数期间 *多次收到SIGQUIT信号都将被屏蔽(阻塞) *SIGINT信号处理函数处理完,立刻解除对 *SIGQUIT信号的屏蔽,由于没有捕捉该信号, *将立刻执行该信号的默认动作,程序退出 */ #include <stdio.h> #include <signal.h> #include <unistd.h> void sig_int(int signo) { printf("catch signal SIGINT "); sleep(10); //模拟信号处理函数执行很长时间 printf("end of handler "); } int main(void) { struct sigaction act; act.sa_handler = sig_int; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGQUIT); /*将SIGQUIT加入信号屏蔽集,这就导致,在调用信号处理函数期间 *不仅不响应SIGINT信号本身,还不响应SIGQUIT*/ act.sa_flags = 0; sigaction(SIGINT, &act, NULL); //注册信号SIGINT捕捉函数 while(1); return 0; }
内核实现信号捕捉过程:
- 上一篇: java数组详解
- 下一篇: java中continue标记的使用