以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
一、信号概述
1、信号是内容受限的一种异步通信机制
(1)信号的目的:用来进程间通信(IPC)、进程和内核间的通信。
(2)信号是异步的(类似于软件中断,对比硬件中断,如按键,不知道什么时候按下)。
(3)信号本质上是 int 型的数字编号,每个编号有特定的含义,内容是十分有限的。
2、信号由谁发出
(1)用户在终端按下按键。
(2)硬件异常后由操作系统内核发出信号(比如,除以0,导致程序出错)。
(3)用户使用kill命令向其他进程发出信号。
(4)某种软件条件满足后也会发出信号。比如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时也会产生SIGPIPE信号。
3、进程如何处理信号
(1)忽略信号。
(2)捕获信号。信号绑定一个信号处理函数,捕获信号后执行该处理函数。
(3)默认处理。当前进程没有明显地管理这个信号,默认忽略或终止进程。
4、常见信号介绍
(1)信号在内核/usr/include/i386-linux-gnu/bits中定义,信号的编号一般从1开始。
(2)其中 SIGKILL 是无法忽略、无法拦截的,但必须有权限。
(3)其中 SIGCHILD 是wait阻塞时期待得到的信号。
二、与信号处理有关的API
1、signal函数
函数模型
#include <signal.h>typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
函数作用
signal函数绑定一个捕获函数后,信号发生后会自动执行绑定的捕获函数,并且把信号编号作为传参传给捕获函数。signal函数的返回值,在函数出错时为SIG_ERR,没有出错则返回信号之前绑定的旧的处理函数。
如何理解呢?看下面的代码。
#include <stdio.h> #include <signal.h>static void SignalHandler1(int signo) {printf("\nhaha\n"); } static void SignalHandler2(int signo) {printf("\nhehe\n"); } int main() {void (*func)(int);if ((func = signal(SIGINT, SignalHandler1)) == SIG_ERR){perror("signal\n");}sleep(10);if ((func = signal(SIGINT, SignalHandler2)) == SIG_ERR) //func 赋值为 signal函数的返回值{perror("signal");}sleep(10);func(2);//注意这里具体是哪个函数。return 0; }
运行结果
^C//第一次触发signal haha//信号处理程序是SignalHandler1,此时signal的返回值是//以前的处理signo的函数指针,应该是系统默认的 ^C//第二次触发signal hehe//信号处理程序是SignalHandler2,此时signal的返回值是//以前的处理signo的函数指针,应该是SignalHandler1haha//所以此处输出的是SignalHandler1的结果
参数说明
(1)signum为信号编号。
(2)handler为信号所绑定的处理方式,它可能为SIG_IGN、SIG_DFL或者函数。分别表示忽略处理、默认处理、执行该函数。
补充说明
(1)signal函数非常简单好用,捕获信号常用。
(2)绑定处理函数的这种方式,使用signal时,不同版本可能不同。
(3)无法直接地得知之前设置的对信号的处理方法。
代码示例
/* 举例:用signal函数处理SIGINT信号(此信号由ctrl+c时发出) 信号出现时,进程对信号的三种处理方式 (1)默认处理 (2)忽略处理 (3)捕获处理 */#include <stdio.h> #include <signal.h> #include <stdlib.h>typedef void (*sighandler_t)(int);void func(int sig) {if (SIGINT != sig)return;printf("func for signal: %d.\n", sig); }int main(void) {sighandler_t ret = (sighandler_t)-2;//signal(SIGINT, func); // 指定信号SIGINT为绑定处理函数//signal(SIGINT, SIG_DFL); // 指定信号SIGINT为默认处理ret = signal(SIGINT, SIG_IGN); // 指定信号SIGINT为忽略处理if (SIG_ERR == ret){perror("signal:");exit(-1);}printf("before while(1)\n");while(1);printf("after while(1)\n");return 0; }
2、sigaction函数
函数模型
补充说明
(1)sigaction比signal更具有可移植性。
sigaction可以单独设置新的捕获,或者单独只获取旧的捕获函数(将新的传参为NULL)。
而signal函数不能单独获取旧的捕获函数,必须设置新的捕获函数,传参后函数返回才获取旧的捕获函数。
(2)用法关键是2个sigaction指针。