一、linux信号是什么
- 基本概念
信号是事件发生时对进程的通知机制,也就是所谓的软件中断。信号和硬件的中断类似,是软件层对中断机制的模拟,在多数情况下是无法预测信号产生的时间,所以软件层提供了一种处理异步事件的方法。
二、 信号来源
信号的来源分为硬件来源和软件来源。
- 硬件来源:
- 硬件发生异常,即硬件检测到错误条件并通知内核,随即再由内核发送相应的信号给相关进程,如除数为0、无效的内存引用等。
- 用户按终端键,引起终端产生的信号(比如Ctrl + C键产生SIGINT)。
- 软件来源:
- 用户通过指令杀死,如kill指令。
- 发生软件事件, 如程序执行raise, alarm、setitimer、sigqueue等函数。
三、 信号处理
信号通常是发送给对应的进程,当信号到达后,该进程需要做出相应的处理措施,通常进程会视具体信号执行相应的操作,有三种操作方式。
- 忽略信号:
信号到达后、直接忽略,就好像是没有出该信号,信号对该进程不会产生任何影响。事实上,大多数信号都可以使用这种方式进行处理,但有两种信号却决不能被忽略,分别是SIGKILL 和 SIGSTOP。 - 捕获信号:
当信号到达进程后,执行signal()绑定好的信号处理函数。 - 执行系统默认操作:
进程不对该信号事件作出处理,而是交由系统进行处理,每一种信号都会有其对应的系统默认的处理方式。
四、常见信号
在linux系统中通过
kill -l
命令可以查看到相应的信号。信号编号是从 1 开始,不存在编号为 0 的信号,事实上 kill()函数对信号编号 0 有着特殊的应用。
注意:括号\” ) \”前面的数字对应该信号的编号,编号 1~31 所对应的是不可靠信号,编号 34~64 对应的是可靠信号,从图中可知,可靠信号并没有一个具体对应的名字,而是使用了 SIGRTMIN+N 或 SIGRTMAXN 的方式来表示。其中32和33空缺。
不可靠信号表
值 | 名称 | 解释 | 默认动作 |
---|---|---|---|
1 | SIGHUP | 挂起 | |
2 | SIGINT | 中断 | |
3 | SIGQUIT | 退出 | |
4 | SIGILL | 非法指令 | |
5 | SIGTRAP | 断点或陷阱指令 | |
SIGABRT | abort发出的信号 | ||
7 | SIGBUS | 非法内存访问 | |
8 | SIGFPE | 浮点异常 | |
9 | SIGKILL | kill信号 | 不能被忽略、处理和阻塞 |
10 | SIGUSR1 | 用户信号1 | |
11 | SIGSEGV | 无效内存访问 | |
12 | SIGUSR2 | 用户信号2 | |
13 | SIGPIPE | 管道破损,没有读端的管道写数据 | |
14 | SIGALRM | alarm发出的信号 | |
15 | SIGTERM | 终止信号 | |
16 | SIGSTKFLT | 栈溢出 | |
17 | SIGCHLD | 子进程退出 | 默认忽略 |
18 | SIGCONT | 进程继续 | |
19 | SIGSTOP | 进程停止 | 不能被忽略、处理和阻塞 |
20 | SIGTSTP | 进程停止 | |
21 | SIGTTIN | 进程停止,后台进程从终端读数据时 | |
22 | SIGTTOU | 进程停止,后台进程想终端写数据时 | |
23 | SIGURG | I/O有紧急数据到达当前进程 | 默认忽略 |
24 | SIGXCPU | 进程的CPU时间片到期 | |
25 | SIGXFSZ | 文件大小的超出上限 | |
26 | SIGVTALRM | 虚拟时钟超时 | |
27 | SIGPROF | profile时钟超时 | |
28 | SIGWINCH | 窗口大小改变 | 默认忽略 |
29 | SIGIO | I/O相关 | |
30 | SIGPWR | 关机 | 默认忽略 |
31 | SIGSYS | 系统调用异常 |
五、信号处理
- signal()
\”signal.h\”信号处理库提供了signal函数,用来捕获突发事件。以下是 signal() 函数的语法ads。
typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);
- signum:可使用信号名(宏)或信号的数字编号,建议使用信号名。
- handler:参数 handler 既可以设置为用户自定义的函数,也可以设置为 SIG_IGN 或 SIG_DFL,SIG_IGN 表示此进程需要忽略该信号,SIG_DFL 则表示设置为系统默认操作。
- raise()
有时进程需要向自身发送信号,raise()函数可用于实现这一要求.
int raise(int sig);
- sig:需要发送的信号。
- sigaction()
除了signal()之外,sigaction()系统调用是设置信号处理方式的另一选择,虽然 signal()函数简单好用,而 sigaction()更为复杂,但作为回报,sigaction()也更具灵活性以及移植性。
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
- signum:需要设置的信号,除了 SIGKILL 信号和 SIGSTOP 信号之外的任何信号。
- act:参数 act 不为 NULL,则表示需要为信号设置新的处理方式;如果参数 act 为 NULL,则表示无需改变信号当前的处理方式
- oldact:参数oldact 不为 NULL,则会将信号之前的处理方式等信息通过参数 oldact 返回出来;如果无意获取此类信息,那么可将该参数设置为 NULL。
- 返回值:成功返回 0;失败将返回-1,并设置 errno。
struct sigaction 结构体
struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);};
- sa_handler:指定信号处理函数,与 signal()函数的 handler 参数相同。
- sa_sigaction:也用于指定信号处理函数,这是一个替代的信号处理函数。
- sa_mask:参数 sa_mask 定义了一组信号。
- sa_restorer:该成员已过时,不要再使用了。
- sa_flags:参数 sa_flags 指定了一组标志,这些标志用于控制信号的处理过程。
- kill()
kill()系统调用可将信号发送给指定的进程或进程组中的每一个进程。
int kill(pid_t pid, int sig);
- pid:参数 pid 为正数的情况下,用于指定接收此信号的进程 pid。
- sig:参数 sig 指定需要发送的信号,也可设置为 0,如果参数 sig 设置为 0 则表示不发送信号,但任执行错误检查,这通常可用于检查参数 pid 指定的进程是否存在。
- 返回值:成功返回 0;失败将返回-1,并设置 errno。
- alarm()
使用 alarm()函数可以设置一个定时器(闹钟),当定时器定时时间到时,内核会向进程发送 SIGALRM信号。 - seconds:设置定时时间,以秒为单位;如果参数 seconds 等于 0,则表示取消之前设置的 alarm 闹钟。
- 返回值:如果在调用 alarm()时,之前已经为该进程设置了 alarm 闹钟还没有超时,则该闹钟的剩余值作为本次 alarm()函数调用的返回值,之前设置的闹钟则被新的替代;否则返回 0。
- pause()
pause()系统调用可以使得进程暂停运行、进入休眠状态,直到进程捕获到一个信号为止,只有执行了信号处理函数并从其返回时,pause()才返回,在这种情况下,pause()返回-1,并且将 errno 设置为EINTR。
unsigned int alarm(unsigned int seconds);
int pause(void);
- 使用案例
demo1
#include <stdio.h>#include <signal.h>#include <stdlib.h>#include <unistd.h>void signal_handler(int signum){printf(\"Interrupt signal (%d) received. \\n\", signum);switch(signum){case SIGINT:printf(\"ctrl + c \\n\");exit(signum);break;case SIGQUIT:printf(\"ctrl + \\\\ \\n\");exit(signum);}}int main(int argc, char *argv[]) {int i = 0;//注册信号与信号处理程序signal(SIGINT, signal_handler);signal(SIGQUIT, signal_handler);while(1){printf(\"Going to sleep....\\n\");if (i > 5){raise( SIGINT);}sleep(1);i++;}return 0;}
参考文献
Linux信号(signal)机制:http://gityuan.com/2015/12/20/signal/
linux 信号及处理过程详解:https://blog.csdn.net/u010765526/article/details/80085895
linux kill信号详解:https://www.geek-share.com/detail/2707194922.html
《正点原子应用编程指南》