中断是系统对于异步事件的响应, 进程执行代码的过程中可以随时被打断,然后去执行异常处理程序;
计算机系统的中断场景:中断源发出中断信号 -> CPU判断中断是否屏蔽屏蔽以及保护现场 -> CPU(查询中断向量表, 找到中断服务程序的入口地址)执行中断处理程序 ->(处理完中断之后) ->恢复现场,继续执行原来的任务
中断分类
硬件中断(外部中断)
外部中断是指由外部设备通过硬件请求的方式产生的中断,也称为硬件中断
软件中断(内部中断)
内部中断是由CPU运行程序错误或执行内部程序调用引起的一种中断,也称为软件中断(如:执行除0操作, 由用户空间陷入内核空间等)。
信号是UNIX/Linux系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。信号一般是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等;信号是在软件层次上对中断的一种模拟,所以通常把它称为是软中断;
信号与中断的相似点:
(1)采用了相同的异步通信方式;
(2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
(3)都在处理完毕后返回到原来的断点;
(4)对信号或中断都可进行屏蔽。
信号与中断的区别:
(1)中断有优先级,而信号没有优先级,所有的信号都是平等的;
(2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;
(3)中断响应是及时的,而信号响应通常都有较大的时间延迟。
常用信号
信号名称 |
描述 |
SIGABRT(6) |
进程停止运行 |
SIGALRM |
警告钟 |
SIGFPE |
算述运算例外(如除0) |
SIGHUP |
系统挂断 |
SIGILL |
非法指令 |
SIGINT(2) |
终端中断 |
SIGKILL |
停止进程(此信号不能被忽略或捕获) |
SIGPIPE |
向没有读者的管道写入数据 |
SIGSEGV |
无效内存段访问 |
SIGQUIT |
终端退出 |
SIGTERM |
终止 |
SIGUSR1 |
用户定义信号1 |
SIGUSR2 |
用户定义信号2 |
SIGCHLD |
子进程已经停止或退出 |
SIGCONT |
如果被停止则继续执行 |
SIGSTOP |
停止执行 |
SIGTSTP |
终端停止信号 |
SIGTOUT |
后台进程请求进行写操作 |
SIGTTIN |
后台进程请求进行读操作 |
进程对信号的响应
忽略信号
不采取任何操作、有两个信号不能被忽略:SIGKILL和SIGSTOP。
[为什么进程不能忽略SIGKILL/SIGSTOP信号。(如果应用程序可以忽略这2个信号,系统管理无法杀死、暂停进程,无法对系统进行管理。)]
捕获并处理信号
内核中断正在执行的代码,转去执行先前注册过的处理程序。
执行默认操作
默认操作通常是终止进程,这取决于被发送的信号。
信号的默认操作:通过 man 7 signal 查看
typedef void (*__sighandler_t) (int);
#define SIG_ERR ((__sighandler_t) -1)
#define SIG_DFL ((__sighandler_t) 0)
#define SIG_IGN ((__sighandler_t) 1)
__sighandler_t signal(int signum, __sighandler_t handler);
参数
signal是一个带signum和handler两个参数的函数,准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数由handler给出
handler这个函数必须有一个int类型的参数(即接收到的信号代码),它本身的类型是void, handler也可以是下面两个特殊值:
SIG_IGN 屏蔽该信号
SIG_DFL 恢复默认行为
//示例1
void handler(int sigNum)
{
cout << "recv a signal = " << sigNum << endl;
}
int main(int argc, char *argv[])
{
signal(SIGINT, handler);
while (true)
sleep(1);
}
RETURN VALUE
signal() returns the previous value of the signal handler, or SIG_ERR on error.
In the event of an error, errno is set to indicate the cause.
int main(int argc, char *argv[])
{
sighandler_t oldHandler = signal(SIGINT, handler);
if (oldHandler == SIG_ERR)
err_exit("signal error");
while (getchar() != '\n')
sleep(1);
// 等价于 signal(SIGINT, SIG_DFL)
if (signal(SIGINT, oldHandler) == SIG_ERR)
err_exit("signal error");
while (true)
sleep(1);
}
//实例: 捕获所有信号, 并打印信号的信息
int main()
{
for (int i = 1; i < NSIG; ++i)
{
if (signal(i, sigHandler) == SIG_ERR)
{
cerr << "signal " << i << ": " << strsignal(i) << " set error";
cerr << ", errno desc: " << strerror(errno) << endl;
}
}
while (true)
pause();
}
void sigHandler(int signo)
{
cout << "catch a signal, signo = " << signo << ", desc: " << strsignal(signo) << endl;
}