目录
1.什么是信号
本质是一种通知机制,用户or操作系统通过发送一定的停号,通知进程,某些事件已经发生,你可以在后续进行处理
1.1.结合进程,分析信号
a.进程要分析信号,必须要识别信号即,进程要接收并且要具备其如何处理的动作。
b.进程如何识别信号呢?通过程序员设置的方式让进程去识别。
c.信号的产生是随机的,所以进程的处理方式可能不是立即处理,而是将信号存储起来,在合适的场合处理。
d.进程会降临是信号进行存储,方便之后的处理。
e.一般而言,信号的产生相对于进程来说是异步的
2.信号的产生
通过键盘的组合键产生
比如:通过Ctrl+c终止进程,是向目标进程发送2号信号,这就是一种通过键盘向进程发送信号,让进程退出了。
处理信号的常见方式:
默认;忽略;自定义(捕捉信号)一共有这三种处理方式。
如何理解这些组合键是如何变成信号的?
键盘的工作方式是通过中断的方式进行的,OS解释组合键,然后在进程列表中查找,找到前台运行的进程,OS将信号写入当前的进程结构中的位图中。
信号发送本质
信号的种类
3.信号处理常见方式概览
1. 忽略此信号。
2. 执行该信号的默认处理动作。
3. 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉 (Catch)一个信号。
4.产生信号
通过终端按键产生信号
调用系统函数向进程发信号
由软件条件产生信号
硬件异常产生信号
5.信号其他相关常见概念
实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞 (Block )某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
6.捕捉信号
先思考一个问题:信号是什么时候被处理的
首先,不是立即被处理的。而是在合适的时候,这个合适的时候,具体指的是进程从用户态切换回内核态时进行处理。
用户态: 处于⽤户态的 CPU 只能受限的访问内存,用户的代码,并且不允许访问外围设备,权限比较低。
内核态: 处于内核态的 CPU 可以访问任意的数据,包括外围设备,⽐如⽹卡、硬盘等,权限比较高。
注意: 操作系统中有一个cr寄存器来记录当前进程处于何种状态
signal函数:
signal(int signum, sighandler_t handler);
第一个参数为信号,可以是信号的编号,也可以是信号的名称,第二个参数是一个回调函数,通过回调函数处理信号,可以为默认,忽略,自定义。默认和忽略 所对应的参数名称为:SIG_DFL,SIG_IDO。自定义的参数需要自己写回调函数去完成。通过回调的方式,去修改对应的信号捕捉方法。
cpp
#include <stdio.h>
#include <signal.h>
void sigcb(int signal)
{
printf("触发本次事件的信号值:%d\n", signal);
}
int main()
{
// 设置SIGINT信号的处理函数为sigcb
signal(SIGINT, sigcb);
// 死循环,等待SIGINT信号触发
while (1)
{
}
return 0;
}
//当您运行这段代码后,在终端中按下Ctrl+C(发送SIGINT信号),"sigcb"函数将被调用,并打印出触发本次事件的信号值。
7.可重入函数
函数的重入指的是一个函数在不同执行流中同时进入运行,其中不可重入指的是一旦重入就有可能会出问题,而可重入就是不管怎么重入都不会有特殊影响
在一个函数中若对全局变量进行了原子操作,则这个函数一定是可重入的
如果一个函数符合以下条件之一则是不可重入的:
调用了malloc或free,因为malloc也是用全局链表来管理堆的。
调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构
8.一些题
自定义信号捕捉函数 signal函数 sigaction函数
SIGSTOP/SIGKILL信号无法被阻塞,无法被自定义,无法被忽视
Ctrl+C会向当前终端的前台进程发送SIGINT信号,中断正在运行在前台的程序
Ctrl+Z会使当前终端的前台进程进入停止态而不是退出
raise接口可以向当前调用进程发送任意信号
未决信号是在从程序运行在内核态返回用户态的时候进行处理
只有自定义处理方式的信号会在用户态进行处理
自定义处理方式的信号会在执行完信号捕捉函数后先返回内核态
1. 一个进程无法被kill杀死的可能有哪些?
A.这个进程阻塞了信号
B.用户有可能自定义了信号的处理方式
C.这个进程有可能是僵尸进程
D.这个进程当前状态是停止状态
都对 ABCD
2.程序运行从用户态切换到内核态的操作:中断/异常/系统调用
I. 整数除以零
II. sin()函数调用
III. read 系统调用
I 会导致程序异常(分母不能为0)
II 库函数并不会引起运行态的切换
III 系统调用接口