马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
目录
1、关于信号的前置知识
1.1.什么是信号?
1.2.为什么要学习信号?
1.3.如何学习信号?
1.4.一些常见的信号
1.5.信号的处理方式
1.6.为什么每一个进程都可以体系调用?
2.信号的产生
2.1.kill命令产生信号
2.2.键盘产生信号
CTRL+c和CTRL+\的区别
2.3.调用体系函数向进程发信号
2.4.软件条件产生信号
2.5.异常产生信号(硬件异常)
2.6.信号产生的小总结
3.信号的保存
3.1三张表底子
阻塞vs忽略:
3.2三张表匹配的操纵和体系调用
3.3.Core和Term
如何打开Linux的core功能呢?
为什么要用核心转储功能呢?
4.信号的处理
4.1.信号什么时间被处理的?
4.2.信号是如何被处理的?
4.3.volatile
1、关于信号的前置知识
1.1.什么是信号?
Linux体系提供的让用户(进程)给其他进程发送异步信息的一种方式。(注意信号和信号量这两者没有任何关系!)
举个例子:
用户输入命令,在Shell下启动一个前台进程。用户按下 Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,表明成信号,发送给目的前台进程前台进程因为收到信号,进而引起进程退出~
进程就是你,操纵体系就是快递员,信号就是快递
1.2.为什么要学习信号?
我们寻常在处理进程的时间,对于停止、删除进程等操纵,体系要求进程要有随时相应外部信号的能力,随后做出反应
1.3.如何学习信号?
根据进程对于团体信号的操纵过程举行学习。
- 信号的产生(kill命令和键盘产生信号)
- 信号的保存
- 信号的处理
1.4.一些常见的信号
用kill -l命令可以察看体系定义的信号列表
数组和名字都可以标识一个信号,名字着实就是宏,注意没有信号0,没有信号32和33
1.5.信号的处理方式
- 信号本身的默认动作
- 自定义处理信号,捕捉信号
- 忽略信号,忽略也代表处理过信号了
所以我们本身是可以更改对信号的处理方式。
1.6.为什么每一个进程都可以体系调用?
写时拷贝的时间拷贝的全部都是用户空间,不会拷贝内核空间
每一个进程都有本身的地址空间,多个进程就会有多个地址空间,但是内核空间只有一份。所以任何一个进程都可以体系调用
2.信号的产生
2.1.kill命令产生信号
当我们输入kill命令去给进程发送信号的时间,本质是OS举行操纵的。
2.2.键盘产生信号
键盘如何产生信号呢?
常见的有CTRL+c,代表中断这个程序;CTRL+ \发送SIGQUIT信号给当前进程,导致该进程退出并天生core转储文件
CTRL+c和CTRL+\的区别
CTRL+\与Ctrl+C不同,后者只是发送SIGINT信号给当前正在运行的进程,导致进程被停止。Ctrl+\会天生core文件,这个文件包含了进程在退出时的内存映像,可以用于调试。如果进程成功天生core文件,那么可以使用调试工具来分析这个文件,以了解进程瓦解时的状态,这对于排盘问题非常有帮助。
2.3.调用体系函数向进程发信号
kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定的信号(本身给本身发信号)。
- kill函数对任意进程发送任意的信号
- raise函数对本身发送任意信号
#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1
abort函数使当前进程接收到信号而异常停止
#include <stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值。
2.4.软件条件产生信号
alarm函数 和SIGALRM信号就是由软件条件产生信号的代表
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动
作是停止当前进程。
这个函数的返回值是0大概是以前设定的闹钟时间还余下的秒数。如果参数seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数
2.5.异常产生信号(硬件异常)
硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。
比方当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常表明 为SIGFPE信号发送给进程。
再好比当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常表明为SIGSEGV信号发送给进程。
注意寄存器只有一个,但是寄存器的数据可以有很多,我们把寄存器中的数据叫做:上下文数据!!!
2.6.信号产生的小总结
当信号产生的时间,如果进程在处理更加重要的事情,我们就临时不能处理到来的信号,我们必须临时要将到来的信号举行临时保存。
那么问题来了,我们将这些信号保存在哪里呢?——进程的PCB中
所以只有OS才有资格写入信号,如果用户也想写入信号,就必须使用OS提供的体系调用。因此,无论信号产生的方式有多少种,最终都是OS亲身动手将信号写入进程的!!!
3.信号的保存
3.1三张表底子
理论上来说我们用3张表就可以保存信号
- 实际执行信号的处理动作称为信号递达(Delivery)
- 信号从产生到递达之间的状态,称为信号未决(Pending)。
- 进程可以选择阻塞 (Block )某个信号。
- 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
- 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
阻塞vs忽略:
忽略是一种信号递达的方式。阻塞仅仅是不让指定信号进程递达
- pending表比特位的位置,表示信号编号,比特位的内容,表示是否收到指定信号
- block表的比特位的位置,表示信号编号,比特位的内容,表示是否阻塞该信号
下面这三张表必要我们横着读,最后一个handler表示对信号的处理方法
这三张表分别表示信号是否阻塞,信号是否担当到,信号的处理动作
所以我们看这张表的时间,不是竖着看,而是横着看每一个信号
3.2三张表匹配的操纵和体系调用
block表对应的是sigprocmask函数
调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若堕落则为-1
如果oset黑白空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set黑白空指针,则 更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都黑白空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明白how参数的可选值。
pending表对应的是sigpending函数
#include <signal.h>
sigpending
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,堕落则返回-1。
handler函数对应的是signal函数。
可以对指定的信号举行用户指定的信号处理。更改信号的处理方式。
下面是利用这几个函数举行编码,小试牛刀。
3.3.Core和Term
大多数信号的默认相应行为都是Core大概Term;
这两种信号都表示停止进程。
区别:
- Term就是普通的停止进程,之后没有其他动作。
- Core不仅会停止进程,还会天生一个核心转储文件。
为什么默认关闭核心转储功能?防止未知的core dump 一直在举行,导致服务器磁盘被打满,所以默认core是关闭的。
如何打开Linux的core功能呢?
使用ulimit -a查看当前资源限制的设定 ;
其中,第一行表现core文件的大小为0,即表示核心转储是被关闭的
通过ulimit -c size 命令来设置Core文件的大小(同时也是打开了核心转储
为什么要用核心转储功能呢?
想通过core定位到进程为什么退出,以及执行到哪行代码退出的
核心转储功能是什么?
将进程在内存中的核心数据(与调试有关)转储到磁盘中形成。
有什么用呢?
帮忙我们举行调试!
4.信号的处理
4.1.信号什么时间被处理的?
符合的时间,什么是符合的时间呢?进程从内核态(操纵体系的状态,权限级别高),切换到用户态(你本身的状态)的时间,信号会被检测并处理
在信号处理的过程(捕捉)中,一共会有4次的状态切换(内核和用户态)
4.2.信号是如何被处理的?
我们使用体系调用大概访问体系数据,着实还是在进程的地址空间内举行切换的
进程无论如何被切换,总能找到OS,我们访问OS,本质就是通过我们的进程的地址空间举行访问
4.3.volatile
volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操纵,都必须在真实的内存中举行操纵
编译器正常处理是将flag的值从内存读取到CPU中举行处理
当前编译器做了一个优化,因为体系以为flag的值定义之后就没有改变,因此直接将内存里flag的值直接放在了CPU 的寄存器中,因此后面代码改变flag值的时间,是在内存当中改变的,CPU中的值不会改变,而程序读取数据是从CPU读取的,因此就会造成毛病,这时间就必要我们的volatile去修饰这个变量,默认从内存中读取!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |