Linux信号-----信号捕捉函数

前言:

信号捕捉函数,顾名思义就是对某一信号做出处理的动作,也就是设置某一信号的对应动作,这里主要介绍signal函数以及sigaction函数。

信号捕捉特性
  1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为@,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不有@来指定,而是用sa_mask来指定(就是struct sigaction这个结构体中的成员变量),调用完信号处理函数,再恢复为@,这时候就会处理sa_mask阻塞的信号。

  2. 当某个信号捕捉函数执行期间,该信号自动被阻塞

  3. 阻塞的常规信号不支持排队,也就是说尽管在该期间内阻塞同一个信号多次,但只会记录一次,也就导致后来的处理动作只有一次。

内核实现捕捉函数过程

在这里插入图片描述

signal函数
//头文件
#include <signal.h>
//函数原型
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

这里的话,第一个参数signum:指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。(因为这两种信号是无法进行捕获的,主要原因是为了系统的安全问题,当我们发现什么黑马程序,我们就可以利用这两个信号杀死进程。)
第二个参数handler:描述了与信号关联的动作,它可以取以下三种值:

  1. SIG_IGN 这个符号表示忽略该信号。
  2. SIG_DFL 这个符号表示恢复对信号的系统默认处理
  3. 就是自己写的自定义函数,用来完成自己想完成的动作

其中sighandler_t,这个其实就是一个函数指针,这里就不再赘述了。

返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。

注:当信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
在这里插入图片描述

举个例子:
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <signal.h>
# include <sys/time.h>

void catch_sig(int sig){
	printf("I catch the %d siganl\n",sig);
	return ;
}

int main(void)
{
	//第一个表示周期,第二个表示第一次发送信号的时间
	//形成了第一次五秒发送SIGALRM信号,然后每三秒发送信号
	struct itimerval st={{3,0},{5,0}};
	printf("begin...\n");
	setitimer(ITIMER_REAL,&st,NULL);
	signal(SIGALRM,catch_sig);
	while(1);
	return 0;
}

在这里插入图片描述



sigaction函数

sigaction函数的功能是检查或修改与指定信号相关联的处理动作

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

signum -> 捕获的信号类型,
act -> 新的信号处理方式
oldact -> 输出先前信号的处理方式(可以为NULL,也就是不关心之前的设置)。这个主要是备份之前信号处理用的

头疼的结构体
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 是一个函数指针,实际上与 signal 函数中的信号处理函数类似

成员sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值

包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理(这个我感觉不常用)

sa_mask 成员用来指定在信号处理函数执行期间需要被屏蔽的信号,也就是临时的信号屏蔽字

sa_flags 成员用于指定信号处理的行为,我就填0,这样就是用sa_handler这个成员,它可以是下面值的“按位或”组合。
◆ SA_RESTART:使被信号打断的系统调用自动重新发起。
◆ SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
◆ SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
◆ SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
◆ SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
◆ SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。

re_restorer 成员已经废弃,直接NULL。

注: signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受到了一定的限制。而 POSIX 标准定义的信号处理接口是 sigaction 函数

在这里插入图片描述

举个例子:
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <signal.h>
# include <sys/time.h>

void catch_sig(int sig){
	printf("I will caych a sig after 5 second!\n");
	int i = 1;
	while(i<5){
		++i;
		sleep(1);
	}
	printf("%d second: I catch the %d sig!\n",i,sig);
	return ;
}

int main(void)
{
	struct sigaction st;
	st.sa_flags = 0;
	st.sa_handler = catch_sig;
	sigemptyset(&st.sa_mask);
	sigaddset(&st.sa_mask,SIGINT);  //捕捉函数执行期间屏蔽ctrl+c组合键中断

	struct itimerval it={{2,0},{3,0}};
	setitimer(ITIMER_REAL,&it,NULL);   //时钟函数,定时发送信号

	sigaction(SIGALRM,&st,NULL);   //注册捕捉函数
	while(1);
	return 0;
}

在这里插入图片描述


一篇不错博客,写这个信号捕捉函数,请点击

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值