时间:2015-07-27 14:19:34 作者:zhijie 来源:系统之家 1. 扫描二维码随时看资讯 2. 请使用手机浏览器访问: https://m.xitongzhijia.net/xtjc/20150727/53879.html 手机查看 评论 反馈
在Linux中信号也称为软中断,进程在收到信号之后在对信号进行处理,可以说就是一个中断的过程。本文就来为大家简单地解析一下Linux信号机制。
1、安装信号处理函数
在系统编程的层面上与信号的处理关系最直接相关的函数有两个,他们用来安装信号处理函数:
sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act,,struct sigaction *oldact);
第一个函数signal比较简单,sighandler_t 是一个别名,其原型是 typedef void (*sighandler_t)(int),他是一个函数指针,接受一个类型为int的参数(信号的编号),返回void。例如要对SIGUSR1信号进行处理:
void handler(int sig)
{
//strsiganl 功能是把信号的编号转为信号说明的字符串
printf(“Rcv a signal:%s”,strsignal(sig));
}
int main()
{
signal(SIGUSR1,handler);
while(1)
;
}
(这段程序其实是有问题的,后面会说到)这段程序本来是一段死循环,但是对他发送SIGUSR1信号,程序会从while中“中断”转去执行handler中的代码。在shell中使用kill命令发送信号SIGUSR1 于是程序就答应出了一段这样的信息:Rcv a signal:User defined signal 1。signal()的用法几乎就是这么简单。但是由于可移植的原因,参与项目开发时,应该使用下面的这个函数。
sigaction()函数的参数中有两个结构体,其man手册原型如下:
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和sa_sigaction其实是在一个union中,他们都是指向信号处理函数的指针。
sa_mask 是要屏蔽的信号,sa_flags 有多种选项。(关于这两点后文再细说)。从sigaction()原型中可以发现参数中有两个struct sigaction参数,其中act是要安装的信号处理,而oldact是用来带回原来的处理方式方便我们处理完信号后的恢复。如果不需要拿回之前的信号处理方式可以把第三个参数置为NULL,反之如果只想得到之前的处理方式而不像安装新的信号处理,可以把第二个参数置为NULL,这点用signal()是办不到的。用sigaction()改写上面的例子是这样的:
1 void handler(int sig)
2 {
3 printf(“Rcv a signal:%s”,strsignal(sig));
4 }
5
6 int main()
7 {
8 struct sigaction act;
9 sigemptyset(&act.sa_mask);
10 act.sa_handler = handler;
11 act.sa_flags = 0;
12 sigaction(SIGUSR1,&act,NULL);
13 while(1)
14 ;
15 }
2、信号阻塞、信号的未决
sigset_t 是一种将信号类型以为位掩码形式存在的数据类型(下文都称之为信号集),他是多种信号的集合(可以保证容纳所有的信号)。操作系统的PCB为每个进程都维护了一个这样的数据类型,并将其内所有的信号阻塞,使他们不可以实时到达进程。当信号屏蔽解除时他们才被传递到进程。在这之间的状态通常被称为未决(pending)。而在信号阻塞期间多次到来的信号,在信号屏蔽解除时只会被报告一次。
对sigset_t 处理有一系列函数,其中POSIX标准有5个
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
这样的函数基本上看参数就能知道怎么用,不在赘述。
glibc中还实现了3个扩展的函数:
int sigisemptyset(sigset_t *set);
int sigorset(sigset_t *dest, sigset_t *left, sigset_t *right);
int sigandset(sigset_t *dest, sigset_t *left, sigset_t *right);
sigprocmask()函数可以检测和更改信号屏蔽集。
每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how
说明
SIG_BLOCK
将set中的信号与原有的取并集,并更新进程的屏蔽字
SIG_UNBLOCK
解除原有的信号集中包含set中的信号,(set补集的交集)
SIG_SETMASK
将进程的屏蔽字设置为set
sigpending函数可以看到信号屏蔽期间那些信号来到过(不计次数的)。
以上就是Linux的信号机制的解析了,当然Linux信号机制是一个相对复杂的系统,本文能够给大家的是一个初步的了解。
发表评论
共0条
评论就这些咯,让大家也知道你的独特见解
立即评论以上留言仅代表用户个人观点,不代表系统之家立场