信号 捕捉
signal 函数
作用:注册一个信号捕捉函数(注册而非创建)
原型:
sighandler_t signal(int signum, sighandler_t handler);
typedef void (*sighandler_t)(int);
案例一: signal函数 捕捉 ctrl+c 触发事件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void sig_catch(int signo)
{
printf("catch you!!! %d\n", signo);
return;
}
int main(int argc, char *argv[])
{
signal(SIGINT, sig_catch);
//
//
//
while(1);
return 0;
}
sigaction 函数
作用:修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)
原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
成功:0;失败:-1,设置errno
参数:
act:传入参数,新的处理方式。
oldact:传出参数,旧的处理方式
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,表使用默认属性。
案例二: sigaction 函数 捕捉 ctrl+c 触发事件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void sig_catch(int signo) //捕捉函数(回调函数)
{
if(signo == SIGINT){
printf(" SIGINT catch you!!! %d\n", signo);
} else if(signo == SIGQUIT){
printf(" SIGQUIT catch you!!! %d\n", signo);
}
return;
}
int main(int argc, char *argv[])
{
struct sigaction act, oldact;
act.sa_handler = sig_catch; //设置回调函数
sigemptyset(&(act.sa_mask)); //设置屏蔽字 清空sa_mask 在捕捉函数期间生效
act.sa_flags = 0; //设置默认属性
int ret = sigaction(SIGINT, &act, &oldact); //注册信号捕捉函数 ctrl + c
if(ret == -1){
sys_err("sigaction error");
}
ret = sigaction(SIGQUIT, &act, &oldact); //注册信号捕捉函数 ctrl + \
while(1);
return 0;
}
信号捕捉特性
- 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为☆。
- XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
- 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
案例三: 验证信号捕捉特性
从结果很容易看出在信号处理函数执行期间,该信号多次递送,那么只在处理函数之行结束后,处理一次。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
void do_sig(int a)
{
printf("hello world!\n");
sleep(10);//休息10秒 让函数执行久一点
}
int main(void)
{
if (signal(SIGINT, do_sig)== SIG_ERR)
{
perror("signal");
exit(1);
}
while (1) {
printf("---------------------\n");
sleep(1);
}
return 0;
}