简述
Linux中信号属于软中断,很多比较重要的应用程序都需要处理信号,并利用信号提供了一种异步事件的方法。在实际的应用中,我们可以使用系统提供的信号,也可以让程序响应我们自定义的相关信号。
Linux信号处理的相关函数
函数signal
signal函数是Linux提供的信号机制中最简单的一个接口,函数接口
#include<signal.h>
void signal(int signo,void (*func)(int));
//signo:需要响应的信号值
//func:响应的处理函数
调用该函数时,相当于向内核注册signo信号,然后当进程捕捉到该信号后,调用func进行处理,其中func的参数为int,一般会被指向添加的信号。
信号集
signal可以让进程响应相关的信号,但signal的只能一次对单个信号进行设置。为了方便对进程中多个信号管理,Linux系统提供了一系列接口。
#include<signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
//若成功:返回0,失败:-1;
int sigismember(const sigset_t *set,int signo);
//若真:返回1,若假:返回0;
对于一个进程,我们可以设定一个sigset_t类型,用来管理进程中的信号,每次需要对信号做相关处理时,则直接在sigset_t上来进行相关处理。另外注意一点在于,信号集管理,只是针对调用进程对信号响应的管理,对回调函数的处理,仍旧交给signal进行信号响应。
下面通过一个例程来了解
#include<iostream>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<signal.h>
#include<string>
void sigquit(int signo){
std::cout<<"signo:"<<"sigquit"<<std::endl;
}
int main(){
/*
* 这里主要是对信号集的操作
* 这里对信号集的操作,增删查改
* */
sigset_t newmask,oldmask,pendmask;//这里使用一个掩摸去捕获获取设置
if(signal(SIGQUIT,sigquit)==SIG_ERR)
perror("SIGQUIT ERRO");
/*下面则利用信号集来实现*/
sigemptyset(&newmask);
sigaddset(&newmask,SIGINT);
sigaddset(&newmask,SIGQUIT);
/*这里对SIGBLOCK进行阻塞,然后看后面的pending的设置*/
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0){
perror("SIGMASK ERRO");
}
sleep(5);
if(sigpending(&pendmask)<0){
perror("pending erro:");
}
if(sigismember(&pendmask,SIGQUIT))
std::cout<<"SIGQUIT PENGING"<<std::endl;
/*然后再进行一个恢复*/
if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
perror("SIG_SETMASK ERRO:");
printf("SIGQUIT unblock");
sleep(5);
return 0;
}
执行结果
wlm@wlm:~/code/example/Linux$ ./sig2
^\
SIGQUIT PENGING
signo:sigquit
SIGQUIT unblock
上面的例子中,包含了一些下面将会了解的一些对信号集的相关操作。但可以大致的了解到,信号集的操作与回调函数的设置。
函数sigprocmask
上面对信号集的操作,就是对一个进程下信号集的添加、删除,除了对信号的添加、删除,Linux还提供了一个函数sigprocmask,来对信号集中的信号进行一个“批处理”设置。
#include<signal.h>
int sigprocmask(int how,const sigset_t *restrict set,sigset_t *restrict oset);
//成功:返回0,失败:返回-1
how提供了三个选择
how | 说明(针对set) |
---|---|
SIG_BLOCK | 该进程新的信号屏蔽字和set取并集(原有的和set取并集) |
SIG_UNBLOCK | 取交集(set中存放了希望取消阻塞的信号) |
SIG_SETMASK | 该进程新的信号屏蔽是set指向的值 |
set为空,则how无意义,oset用来收上一次的屏蔽字。
函数sigpending
#include<signal.h>
int sigpending(sigset_t *set);
//成功返回0,失败返回-1
sigpending的作用,则是返回该进程中被阻塞的信号。
函数sigsuspend
#include<signal.h>
int sigsupend(const sigset_t *sigmask)
当我们设置了一个A信号,并等待响应,但是在实际开发中,可能出现一种情况,在响应A之前,进程突然接收了其他信号,并退出了程序,导致进程还未对A信号进行配置,无法接收,那么sigsuspend的作用,形象点解释,就是sigprocmask后pasue的原子操作,sigsuspend就是要保证信号被配置,并等待(在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程会被挂起)
函数signaction
对signal升级的安全…待
其他
除了一些基本的信号设置的api外,还有其他一些概念值得我们去注意:可重入函数、信号的可靠去,信号的未决的调解,等问题。