Unix环境高级编程(三)信号专题(1)
原文连接:访问原文
中断的概念
要了解信号的概念,先要了解什么是中断?中断是系统对于异步事件的响应,所谓异步事件的响应就是指:
进程执行代码的过程中可以随时被打断,然后去执行异常处理程序生活中的中断和计算机系统中的中断。
中断的组成包括:
中断信号
* 中断源
* 现场信息
* 中断处理程序
* 中断向量表
这和我们生活中的一些例子很像,比如:张三看书,设置闹钟,厨房烧水。闹钟发出中断信号,张三把书合好(第20页),去厨房把开水事情处理好,张三重新打开20页进行阅读。
其中中断分为两类:硬中断和软中断
硬中断也称外部中断,是指由外部设备通过硬件请求的方式产生的中断,也称为硬件中断。
软中断也称内部中断,是由CPU运行程序错误或执行内部程序调用引起的一种中断,也称为软件中断。
信号的概念
信号是在软件层次上对中断的一种模拟,所以通常把它称为是软中断。
首先,每个信号都有一个名字。这些名字都以三个字符SIG开头。例如,SIGABRT是夭折信号,当进程调用abort
函数时产生这种信号。
信号的定义在头文件<signal.h>
中这些信号都被定义为正整数,范围在1~64。其中1~32号信号是不可靠信号,33~64为前32种不可重入信号的可靠版本,其名称在不可靠信号名称加R
。我们可以通过命令kill -l
来查看Linux内核支持的信号,64中信号如下:
信号和中断的异同
- 信号与中断的相似点:
- 采用了相同的异步通信方式;
- 当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
- 都在处理完毕后返回到原来的断点;
- 对信号或中断都可进行屏蔽。
- 信号与中断的区别:
- 中断有优先级,而信号没有优先级,所有的信号都是平等的;
- 信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;
- 中断响应是及时的,而信号响应通常都有较大的时间延迟。
信号名称及常用信号
信号名称 | 描述 |
---|---|
SIGABRT | 进程停止运行 |
SIGALRM | 警告钟 |
SIGFPE | 算述运算例外 |
SIGHUP | 系统挂断 |
SIGILL | 非法指令 |
SIGINT | 终端中断 |
SIGKILL | 停止进程(此信号不能被忽略或捕获) |
SIGPIPE | 向没有读者的管道写入数据 |
SIGSEGV | 无效内存段访问 |
SIGQUIT | 终端退出 |
SIGTERM | 终止 |
SIGUSR1 | 用户定义信号1 |
SIGUSR2 | 用户定义信号2 |
SIGCHLD | 子进程已经停止或退出 |
信号的处理
进程对信号有三种处理:
1. 忽略信号
不采取任何操作、有两个信号不能被忽略:SIGKILL(9号信号)和SIGSTOP。
2. 捕获并处理信号
内核中断正在执行的代码,转去执行先前注册过的处理程序。SIGKILL(9号信号)和SIGSTOP不能被捕获。
3. 执行默认操作
默认操作通常是终止进程,这取决于被发送的信号。
这里要理解为什么以上两种信号(SIGKILL和SIGSTOP)不能被忽略。其原因是:如果应用程序可以忽略这2个信号,系统管理无法杀死、暂停进程,无法对系统进行管理。
signal函数
signal函数有两个作用:
1. 站在应用程序的角度,注册一个信号处理函数;
2. 忽略信号、设置信号默认处理 信号的安装和恢复。
其函数定义如下:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum指定信号种类,handler指定信号的处理函数,也可以是下面两个特殊值:SIG_IGN(屏蔽该信号)和 SIG_DFL(恢复默认行为)。
signal返回原先的信号处理句柄,出错时返回SIG_ERR,并设置error值。
singnal编程实战
我们先来写一个信号处理函数,这个信号处理函数,实现打印信号值得功能,并且判断信号是否是SIGQUIT,如果是就退出进程。
void handler(int num)
{
printf("recv num:%d \n", num);
}
在主函数中,我们注册此信号,并使进程进入暂停此时用户按(ctrl+c)将执行打印函数,程序无法退出,直到用户键入字符‘a’为止,我们让信号恢复默认行为,再执行==ctrl+c==时,程序退出。
void main()
{
char tmpchar;
signal(SIGINT, handler);
printf("if you input 'a' will recove the default behavior of signal\n");
while((tmpchar = getchar()) != 'a')
{
pause();
}
//让这个信号恢复默认行为
signal(SIGINT, SIG_DFL);
while(1)
{
pause();
}
printf("main----end\n");
}