首页 > 代码库 > 基于 linux的 信号详解
基于 linux的 信号详解
1、信号:
每个信号都一个一个名字,都已SIG开头;不存在编号为0的信号;
2、产生信号的条件:
a、用户使用了终端按键;
b、硬件异常(如除0,无效的内存引用);
c、进程调用kill(2)函数,将信号发送给另一个进程;(注意,另一进程必须和发送进程的的所有者必须相同,或者发送信号的所有者必须是超级用户);
d、当检查到某种软件条件已经发生时,将其通知相关进程时,也产生信号;
3、信号是异步事件的经典;信号的产生是随机的,进程不能通过测试一个变量来测试是否出现了信号,而是必须告诉内核,在该信号出现时,请执行下列操作;
4、内核对出现的信号可有三种动作可选:
a、忽略此信号(注意:SIGKILL 信号 和 SIGSTOP信号,不可被忽略);
b、捕捉信号;简单来说,就是抓到该信号后,执行进程提供给内核的处理函数;注意,SIGKILL和SIGSTOP不可被捕获;
c、执行默认动作;每种信号都有默认动作,大多数信号的默认动作是终止进程;
5、常见信号解释:
a、SIGCHLD 在一个进程终止时,将SIGCHLD信号发送给其父进程;
b、SIGFPE 算数异常;
c、SIGPIPE 写管道,但是管道的读端已经终止,会产生此信号;
d、SIGPWR 不间断电源(UPS)失效;
e、SIGSEGV 无效的内存引用;
f、 SIGSTOP 终止进程;
g、SIGSYS 无效的系统调用;
h、SIGTERM 由kill(1)命令发送的终止信号;
i、 SIGXFSZ 进程超过了其软文件长度的限制;
6、信号处理函数:
Sigfunc *signal(int, Sigfunc*);
参数1:信号宏;
参数2:处理函数;
特殊情况:有几个默认的函数宏,用户默认,忽略,错误处理;
#define SIG_ERR (void (*)()) -1;
#define SIG_DFL (void (*)()) 0;
#define SIG_IGN (void (*)()) 1;
返回值:函数指针;
7、kill(1) 命令和kill(2)函数只是将一个信号送给一个进程或者进程组,信号是否终止,取决于信号的类型,以及进程是否安排了捕捉该信号;
8、当一个进程用fork时,其子进程继承父进程的信号处理方式;
9、 pause函数;
#include <unistd.h>
int pause(void);
该函数,是本进程挂起,指导捕捉到一个信号;只有执行了信号处理函数,并从其中返回时,pause才会返回;在这种情况下,返回是-1;并将error设置为EINTR;
pause函数,使自己休眠,直到捕捉到一个信号;
10、当捕捉到某个信号是,被中断的是内核中执行的系统调用;
12、不可重入函数的原因:
a、该函数使用了静态数据结构;
b、调用了malloc或者free;
c、使用了表中I/O函数,因为表中I/O函数,很多实现都使用了全局的数据结构;
13、在信号产生和信号递达的间隔内,信号处于未决状态;
14、每个信号都有一个信号屏蔽字,该信号屏蔽字规定了要阻塞送到该进程的的信号集。当某个信号递送时即将到达时,发现对应位被设置,则他当前是被阻塞的;
15、kill函数:
#include<signal.h>
int kill(pid_t pid, int signo);
作用:将信号发送给某个进程或者进程组;
参数1: pid > 0,表示将该信号发送给ID 为pid的进程;
pid == 0 ; 将进程发送给本组所有进程;
pid < 0 ,将信号发送给进程组ID 等于 pid绝对值的组;
pid == -1; 表示该进程把信号发送给 “所有自己有权发送给”的那些进程;
16、将编号为0 的信号定义为空信号,使用kill时,signo为0 ,可以进行错误检查,但是不发任何信号,这常被用来测试一个进程是否存在,如果不存在,则返回-1;并将error置为ESRCH;
17、raise函数;
int raise(int signo)函数,用于向进程自身发送信号;
18、alarm函数:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
使用该函数,设定一个定时器,定时器过期时,会产生SIGALRM信号,该信号的默认动作是终止进程;
每个进程同时只能有一个alarm,否则,新使用的alarm会替代旧的alarm,新alarm 会将旧alarm所剩余的时间返回;
将seconds可以取消以前的闹钟,返回余留值;
注意:如果要使用alarm函数,且在在捕捉到SIGALRM信号后,要做相应的处理,则应该在调用alarm函数之前,设置该信号的处理函数;
19、信号集:
信号集:告诉内核不允许发生该信号集中的信号;
五个基本的信号集操作函数:
#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);
删除信号;
int sigismember(const sigset_t *set, int signo);
判断signo是否是信号集成员;
20、sigprocmask函数
#include<signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
成功则返回0,出错返回-1;
当oset 为非空指针时,进程的当前信号屏蔽字通过oset返回;
当set不是空指针时,how用来说明修改当前信号屏蔽字的方式,修改方式包括:SIG_BLOCK(set 和 oset的并集);SIG_UNBLOCK(oset与 “set 信号集的补集“的交集)
SIG_SETMASK(指定用set替代旧的信号集);
21、 sigpending 函数:
用于返回被阻塞而不能递送的信号集;
22、sigaction函数;
功能是检查或者修改与指定信号的相关联的处理动作;与signal作用类似;
#include <signal.h>
int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
返回值:成功则返回0, 出错返回-1;
signo : 表示要检查或者修改具体动作相关联的某个信号;
struct sigaction 结构体:
struct sigaction{
void (*sa_handler)(int) ; //与信号相关的处理函数或者SIG_IGN,SIG_DEF;
sigset_t sa_mask; //信号集;在调用该函数之前,首先应该用此设置信号集;
int sa_flags; //包含对信号处理的各个选项;
void (*sa_sigaction)(int, siginfo_t *, void *); 当在flag中使用了SA_SIGINFO标志时,使用此处理程序;(注意,此函数指针和第一个处理信号的函数指针,两者只能使用其中之一;)zaisiginfo_t结构体中包含了信号产生原因的相关信息;
本文出自 “10891086” 博客,请务必保留此出处http://10901086.blog.51cto.com/10891086/1917537
基于 linux的 信号详解