目录
1. 信号概念
信号就是程序要执行某件事情之前发送的信号,通知进程要做什么事情,是一个软件中断,信号是进程之间事件异步通知的一种方式。
下面用一个具体的例子解释信号。在日常生活中有非常多种的信号,比如说在过马路时,红灯不通行,绿灯通行。这就是一个发送给行人与车辆的信号。
在linux种,写了一个程序,但是这个程序因为某种原因,没有办法正常结束了,可以通过 ctrl+c
强制的结束掉这个进程。在这个过程中,使用ctrl+c
产生了一个硬件的中断,给进程发送了一个结束的信号,进程接收到这个信号并且立即处理这个信号,结束进程。
2. 信号的种类
在linux中,共有62种信号可以通过 kill -l
命令进行查看.
1. 非可靠信号(非实时信号)
在信号分类中,1-31
号信号被称为非可靠信号,即受到上述信号后,进程不会立即处理该信号,信号有可能会丢失。
2. 可靠信号(实时信号)
34-64
号信号被称为可靠信号,信号绝对不会丢失。
3. 信号的处理流程
- 在信号处理信号时,当处理完某些功能,进入内核态后,处理完异常之后,一定会调用
do_signal
函数,在函数中会检测当前有没有要处理的信号,如果有则判断是否执行默认处理,还是自定义的处理方式,处理完成后才会返回用户态,如果没有则直接返回用户态。- 执行流从内核态切换到用户态之前一定会调用
do_signal
函数处理信号- 从用户态切换到内核态时,是调用了系统调用函数,或者进程异常
4. 信号的产生方式
4.1 软件产生
1. 命令产生
kill
命令: 可以通过kill -num
的方式向进程中发送指定的信号.
2. 函数产生
int kill(pid_t pid, int sig);
// 参数: pid要发送信号的进程pid
// sig发送信号的序号
/
int raise(int sig);
// 作用:向自身发送信号,内部封装了kill函数
/
unsigned int alarm(unsigned int seconds);
// 作用:参数传递一个秒数,在事件到达之后发送一个SIGALRM信号
代码测试
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
//kill(getpid(), 2);
raise(2);
// 如果没有打印这一句 说明上述语句没有发送成功
printf("hello");
return 0;
}
4.2 硬件产生
ctrl+c
: 发送的为2号信号即SIGINT
ctrl+z
: 发送的为3号信号即SIGQUIT
ctrl+|
: 发送的为20号信号即SIGSTP
5. 信号的注册
信号的注册是通过改变signal位图中的比特位进行信号的注册。
linux中信号的种类共有62个,但用于存储信号的变量只有2个long的长度,共128个字节,如果一个变量存储一个是远远不够的,所以采用 位图 的方式进行存储信号,数组中对应的每一位存储一个信号,有信号则置为1,无则保持为0。并且数组的每一位没有全部使用,含有预留位置。
并且signalpending
结构体中含有一个sigqueue队列
,信号接收到进行注册时,需要在sigqueue队列中添加结点
- 非可靠信号的注册
第一次: 将信号对应的比特位置为1,在sigqueue队列中添加sigqueue结点
第二次: 只会将信号对应的比特位从1改为1,不会添加sig