在细说信号之前我们先来了解下什么是信号。信号(signal)是一种软件中断,它提供了一种处理异步事件的方法,也是进程间惟一的异步通信方式。在Linux系统中,根据POSIX标准扩展以后的信号机制,不仅可以用来通知某种程序发生了什么事件,还可以给进程传递数据。
信号的种类有很多,我们可以通过kill -l命令察看系统定义的信号列表:
可以看到一共有62个信号。1-31号为普通信号;34-64号为实时信号。(博主这次只讨论普通信号。)
接下来我们来细说信号的产生、阻塞和捕捉。
>>信号的产生:
通过终端按键产生信号 ;
通过下面的代码写一个死循环:
可以通过键盘输入Ctrl+\进行终止该进程:
调用系统函数向进程发信号;
在后台执行死循环程序,然后用kill命令给它发SIGSEGV信号:(按两次回车)
用软件条件产生信号;
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发 SIGALRM信号, 该信号的默认处理动作是终止当前进程。这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。
该程序是用在1秒钟内不停的计数,直到1秒中到了被SIGALRM信号终止掉进程。
>>阻塞信号
信号在内核中的表示:
实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞 (Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞, 才执行递达的动作。
Notice:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
信号在内核中的表示示意图:
每个信号都有两个标志位来表示阻塞和未决和一个函数指针来表示处理动作。
信号集操作函数:
sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这 些bit则依赖于系统实现不是我们所关心的问题。
我们可以通过调用以下函数来进行操作sigset_t变量
int sigemptyset(sigset_t *set);//初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号
int sigfillset(sigset_t *set);//初始化set所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括系统支持的所有信号
int sigaddset(sigset_t *set, int signo);//在该信号集中添加或删除某种有效信号
int sigdelset(sigset_t *set, int signo);//在该信号集中添加 或删除某种有效信号
int sigismember(const sigset_t *set, int signo); //是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0, 出错返回-1
sigprocmask 函数和sigpending 函数
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。若成功则为0,若出错则为-1。
int sigpending(sigset_t *set);
sigpending读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回 -1。
结果如下:
上述程序利用printsigset()函数将指定信号集的所有信号的存在情况打印出来。
sigprocmask 执行完毕后,SIGINT信号就相当于被阻塞了。
本文出自 “七月朔风” 博客,请务必保留此出处http://luminous.blog.51cto.com/10797288/1825779
原文地址:http://luminous.blog.51cto.com/10797288/1825779