何为信号:信号就是由用户、系统或进程发送给目标进程的信息,以通知目标进程中某个状态的改变或是异常。
信号产生:总体来说,其产生的条件有两种,分别是:硬件和软件原因,又称为:硬中断和软中断。可细分为如下几种原因:
①系统终端Terminal中输入特殊的字符来产生一个信号,比如按下:ctrl+\会产生SIGQUIT信号。
②系统异常。比如访问非法内存和浮点数异常。
③系统状态变化。如设置了alarm定时器,当该定时器到期时候会引起SIGVTALRM信号。
④调用了kill命令或是kill函数。
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)捕捉该信号。这里需要用户自定义一个函数,来对产生的信号进行捕捉,而在这个函数中可执行用户希望对这个事件进行的处理操作。
在处理由系统产生的一个信号时候,首先得对产生的该信号进行安装登记,这样才能对其进行处理。何为安装登记呢?其实很好理解,好比你去图书馆借阅图书,当你找到了喜欢的书籍后,再用借书卡去机器上面扫描登记,然后就可以带走该书籍去阅读了。这里的图书相当于信号,用借书卡登记和对信号进行登记同个道理,处理信号相当于你将书籍带离图书馆阅读。Linux上有两个函数都可用来对信号进行登记,分别是:signal和 sigaction 。
这两个函数的区别:
(1)signal是在系统调用的基础上实现,是库函数,它有两个参数,不支持信号传递信息,主要用于kill -l 中的前32个非实时信号的安装。
(2)sigaction是较新的函数,(由sys_signal和sys_rt_sigaction两个系统调用实现 ),有3个参数。支持信号传递信息,主要用来和sigqueue系统调用配合使用。
#include
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: [email protected]
* 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值进行比较。
在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效果相同 |