1. 信号概述 何为信号:信号就是由用户、系统或进程发送给目标进程的信息,以通知目标进程中某个状态的改变或是异常。 信号产生:总体来说,其产生的条件有两种,分别是:硬件和软件原因,又称为:硬中断和软中断。可细分为如下几种原因: ①系统终端Terminal中输入特殊的字符来产生一个信号,比如按下:ctrl + </font>会产生SIGQUIT信号。 ②系统异常。比如访问非法内存和浮点数异常。 ③系统状态变化。如设置了alarm定时器,当该定时器到期时候会引起SIGVTALRM信号。 ④调用了kill命令或是kill函数。 1. 1 系统如何处理信号 Linux系统对于接收到的信号(无论是硬中断还是软中断)可以有三种处理方式: (1)忽略此信号。SIG_IGN,该常数表示信号函数的忽略。在/usr/include/x86_64-linux-gnu/bits/signum.h 头文件中有SIG_IGN的宏定义 #define SIG_IGN ((__sighandler_t) 1) /* 忽略信号 */
(2)执行系统默认的动作。SIG_DFL,该常数表示信号的默认值。对于大多数的系统来说,系统的默认动作就是终止该进程。在/usr/include/x86_64-linux-gnu/bits/signum.h 头文件中有SIG_IGN的宏定义 #define SIG_DFL ((__sighandler_t) 0) /* 默认动作 */
值得注意的是:Linux下的系统默认动作一般有如下几种: ①结束进程(Term) ②忽略信号(Ignore) ③结束进程并生成核心转储文件(Core),该文件用于gdb后期调试 ④暂停进程(Stop) ⑤继续进程(Continue),如果进程被挂起,则恢复进程的运行。否则,忽略该信号。 (3)捕捉该信号。这里需要用户自定义一个函数,来对产生的信号进行捕捉,而在这个函数中可执行用户希望对这个事件进行的处理操作。
2. 使用signal函数捕捉信号 在处理由系统产生的一个信号时候,首先得对产生的该信号进行安装登记,这样才能对其进行处理。何为安装登记呢?其实很好理解,好比你去图书馆借阅图书,当你找到了喜欢的书籍后,再用借书卡去机器上面扫描登记,然后就可以带走该书籍去阅读了。这里的图书相当于信号,用借书卡登记和对信号进行登记同个道理,处理信号相当于你将书籍带离图书馆阅读。Linux上有两个函数都可用来对信号进行登记,分别是:signal和sigaction。 对于sigaction的使用请参考 这两个函数的区别: (1)signal是在系统调用的基础上实现,是库函数,它有两个参数,不支持信号传递信息,主要用于kill -l 中的前32个非实时信号的安装。 (2)sigaction是较新的函数,(由sys_signal和sys_rt_sigaction两个系统调用实现 ),有3个参数。支持信号传递信息,主要用来和sigqueue系统调用配合使用。
2.1 signal详解 #include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
- 函数说明:设置信号处理方式。signal()会依参数signum指定的信号编号(0~64)来设置该信号 的处理函数。当指定的信号到底时,就会跳转到参数handler指定的函数执行。 #define SIG_ERR ((__sighandler_t) -1) /* 错误返回 */
代码1 /*************************************************************************
* File Name: signal.cpp
* Author: The answer
* Function: Other
* Mail: 2412799512@qq.com
* Created Time: 2018年05月13日 星期四 18时47分11秒
************************************************************************/#include <iostream>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>using namespace std;void sig_handler(int signum){
if(0 > signum)
{
fprintf(stderr,'sig_handler param err. [%d]\n',signum);
return;
}
if(SIGINT == signum)
{
printf('Received signal [%s]\n',SIGINT==signum?'SIGINT':'Other');
}
if(SIGQUIT == signum)
{
printf('Received signal [%s]\n',SIGQUIT==signum?'SIGQUIT':'Other');
}
return;}int main(int argc,char **argv){
printf('Wait for the signal to arrive.\n ');
/*登记信息*/
signal(SIGINT,sig_handler);
signal(SIGQUIT,sig_handler);
pause();
pause();
signal(SIGINT,SIG_IGN);
return 0;}
程序运行后会一直等待用户的输入,当在终端按下ctrl+c时候会打印^C Received signal [SIGINT] 说明捕获到了SIGINT信号,接着程序继续等待,当按下ctrl+\时候会打印^\Received signal [SIGQUIT] 表明捕获到了SIGQUIT信号,如下图所示:
在Linux的目录/usr/include/x86_64-linux-gnu/bits/signum.h下有对所有信号的宏定义,所以可以用来和int值进行比较。
3. Linux标准信号 在Linux终端下 kill -l 可以查看所有的信号。
这里是上面64种信号的说明: 信号 | 起源 | 默认行为 | 含义 |
---|
SIGHUP | POSIX | Term | 控制终端挂起 | SIGINT | ANSI | Term | 键盘输入以终端进程(ctrl + C) | SIGQUIT | POSIX | Core | 键盘输入使进程退出(Ctrl + \) | SIGILL | ANSI | Core | 非法指令 | SIGTRAP | POSIX | Core | 断点陷阱,用于调试 | SIGABRT | ANSI | Core | 进程调用abort函数时生成该信号 | SIGIOT | 4.2BSD | Core | 和SIGABRT相同 | SIGBUS | 4.2BSD | Core | 总线错误,错误内存访问 | SIGFPE | ANSI | Core | 浮点异常 | SIGKILL | POSIX | Term | 终止一个进程。该信号不可被捕获或被忽略 | SIGUSR1 | POSIX | Term | 用户自定义信号之一 | SIGSEGV | ANSI | Core | 非法内存段使用 | SIGUSR2 | POSIX | Term | 用户自定义信号二 | SIGPIPE | POSIX | Term | 往读端关闭的管道或socket链接中写数据 | SIGALRM | POSIX | Term | 由alarm或settimer设置的实时闹钟超时引起 | SIGTERM | ANSI | Term | 终止进程。kill命令默认发生的信号就是SIGTERM | SIGSTKFLT | Linux | Term | 早期的Linux使用该信号来报告数学协处理器栈错误 | SIGCLD | System V | Ign | 和SIGCHLD相同 | SIGCHLD | POSIX | Ign | 子进程状态发生变化(退出或暂停) | SIGCONT | POSIX | Cont | 启动被暂停的进程(Ctrl+Q)。如果目标进程未处于暂停状态,则信号被忽略 | SIGSTOP | POSIX | Stop | 暂停进程(Ctrl+S)。该信号不可被捕捉或被忽略 | SIGTSTP | POSIX | Stop | 挂起进程(Ctrl+Z) | SIGTTIN | POSIX | Stop | 后台进程试图从终端读取输入 | SIGTTOU | POSIX | Stop | 后台进程试图往终端输出内容 | SIGURG | 4.3 BSD | Ign | socket连接上接收到紧急数据 | SIGXCPU | 4.2 BSD | Core | 进程的CPU使用时间超过其软限制 | SIGXFSZ | 4.2 BSD | Core | 文件尺寸超过其软限制 | SIGVTALRM | 4.2 BSD | Term | 与SIGALRM类似,不过它只统计本进程用户空间代码的运行时间 | SIGPROF | 4.2 BSD | Term | 与SIGALRM 类似,它同时统计用户代码和内核的运行时间 | SIGWINCH | 4.3 BSD | Ign | 终端窗口大小发生变化 | SIGPOLL | System V | Term | 与SIGIO类似 | SIGIO | 4.2 BSD | Term | IO就绪,比如socket上发生可读、可写事件。因为TCP服务器可触发SIGIO的条件很多,故而SIGIO无法在TCP服务器中用。SIGIO信号可用在UDP服务器中,但也很少见 | SIGPWR | System V | Term | 对于UPS的系统,当电池电量过低时,SIGPWR信号被触发 | SIGSYS | POSIX | Core | 非法系统调用 | SIGUNUSED |
| Core | 保留,通常和SIGSYS效果相同 |
|