Linux 进程信号


前言

进程信号---------信号量不是信号

一、信号是什么?

信号是什么:信号是一个软件中断;
举例:正在上课,听到了下课铃声
作用:操作系统通过信号告诉进程发生了某个事件,打断进程当前的操作,去处理这个事件。
生活中的信号多种多样,并且肯定是一个信号对应一个事件,并且我们能够识别这个信号。
操作系统中的信号也同样如此:通过kill -l命令可以查看系统中的信号种类–62种
在这里插入图片描述

1-31号信号:从unix借鉴而来的,每个信号都有具体对应的系统事件;-----非可靠信号(有可能会信号丢失–事件丢失)
34-64号信号:后期扩充的,因为没有具体对应的事件,因此命名比较草率------可靠信号(不会丢失信号)
信号的生命周期:产生->在进程中注册->在进程中注销->处理

二、信号的产生

产生:
硬件:ctrl+c 中断进程/ctrl+z/ctrl+l
软件:kill -signum pid命令
kill 默认发送第15号信号
kill(int pid,int signum)
raise(int signum)
abort() 给自己发送SIGABRT信号-通常用于异常通知
alarm(int seconds) 定时器 设定秒钟之后给进程自己发送SIGALRM信号
kill杀死一个进程的原理就是,向进程发送一个信号,信号有对应的事件,进程放下手头工作去处理这个事件,然而事件的处理就是让进程退出

三、信号在进程中注册

如何让进程知道自己收到了某个信号;
pcb->struct sigpending -> struct sigset_t
sigset_t 这个结构体中只有一个数组成员;这个数组用于实现一个位图—称之为未决信号集合–收到了但是没有被处理的信号集合
给一个进程发送一个信号,就会将这个位图中对应位置1,表示进程当前收到了这个信号
但是位图只有0/1,也就是只能表示是否收到了这个信号,但是无法表示收到多少个这样的信号
信号的注册其实不仅会修改位图,还会为信号组织一个sigqueue节点添加到pcb的sigqueue链表中
1~31号非可靠信号的注册:若信号注册位图为0,则会创建一个sigqueue节点并修改位图为1,但是若位图为1,则什么都不做
34~64号可靠信号的注册:不管位图当前是否为0,则会创建一个节点,添加到链表中,并修改位图

举例:肚子叫这种信号,不管通知多少次,只需要处理一次;数据请求,每一次都需要处理;
在这里插入图片描述

四、信号在进程中注销

为了保证一个信号只会被处理一次,因此是先注销在再处理;在pcb中删除当前信号信息
将pending位图置0;删除信号节点;
非可靠信号注销:因为非可靠信号只会有一个节点,因此删除节点后,位图直接置0;
可靠信号注销:因为可靠信号有可能注册多次,有多个节点,因此删除节点后,需要判断是否还有相同节点,若没有才会将位图置0

五、信号的处理

信号表示一个事件的到来,处理事件就是完成功能,在C语言中完成一个功能的最小模块–函数
其实每一个信号都对应有自己的事件处理函数,信号到来,去处理这个事件就是去执行这个处理函数;执行完毕事件就处理完了
信号的处理方式:
1.默认处理方式:操作系统中原定义好的每个信号的处理方式
2.忽略处理方式:处理方式就是忽略,什么都不做
3.自定义处理方式:自己定义一个事件函数,使用这个函数替换内核中默认的处理函数;信号到来就会调用我们定义的函数了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

六、信号阻塞

并不是不接收信号。信号依然可以注册,只是标识哪些信号暂时不处理;
在pcb中有一个位图,位图叫block位图–阻塞信号集合;这个集合中的信号如果来了(添加到pending位图了)则暂时不处理
在这里插入图片描述

如何阻塞一个信号:
int sigprocmask(int how,sigset_t *set,sigset_t *old)
how:
SIG_BLOCK----将set集合中的信号添加到内核中的block阻塞信号集合中,使用old保存原来的阻塞信息以便于还原
SIG_UNBLOCK----将set集合中的信号从内核中的block阻塞信号集合中移除—对set集合中的信号解除阻塞
SIG_SETMASK----将内核中的block阻塞信号集合内容设置为set集合中的信息–阻塞set集合中的信号
SIG_BLOCK --set|block /SIG_UNBLOCK–~set&block /SIG_SETMASK—block=set
0.将一些信号的处理函数自定义; 1.将所有的信号都给阻塞;2.在解除阻塞之前,给进程发送信号;3。解除阻塞,查看信号的处理情况

int sigemptyset(sign_t set);//清空set信号集合—使用一个变量的时候的初始化过程
int sigaddset(sigset_t
set,int signum);//向set集合中添加指定的信号
int sigfillset(sigset_t *set);//将所有信号添加到set集合中
int sigdelset(sigset_t *set,int signum);//从set集合中移除指定的信号
int sigismember(const sigset_t *set,int signum);//判断指定信号是否在set集合中

在这里插入图片描述

在所有的信号中,有两个信号比较特殊:SIGKILL-9/SIGSTOP-19,这两个信号不可被阻塞,不可被忽略,不可被自定义
在进程间通信这节课中,我们学习管道的时候,说了一个信息,所有管道读端被关闭,则继续写入会触发异常-SIGPIPE

僵尸进程:子进程退出后会向父进程发送SIGCHLD信号通知父进程,子进程的状态改变;
但是因为SIGCHLD信号,默认的处理方式是忽略;因此之前的程序中若不进行进程等待则不知道子进程退出
学习了信号之后,就要理解,如果进行进程等待,而且还不想让父进程阻塞,就可以自定义SIGCHLD信号的处理方式;
在自定义回调函数中调用waitpid,处理僵尸进程,父进程就不用一直等待

但是SIGCHLD信号是一个非可靠信号,如果有多个子进程同时退出,有可能造成信号丢失
解释:非可靠信号注册:修改位图,添加一个信号节点,(若有相同信号已经注册未处理,则不再注册)
可靠信号注册:修改位图,添加一个信号节点,(不管是否已经注册都会添加一个节点)
所以注销时非可靠因为只有一个节点,因此只需要处理一次就会注销
一个进程有10个子进程退出,则10个子进程都会向一个父进程发送信号,这就是存在丢失可能的原因,因为他们的信号发送给同一个进程了
跟子进程pid不同,有各自的信号位图没关系,各个进程的信号位图是保存发送给自己的信号的

while(waitpid(-1,NULL,WNOHANG)>0);非阻塞循环在一个回调中将所有的僵尸进程全部处理

关键字volatile:用于修饰一个变量,保持变量的内存可见性(cpu在处理的时候每次都重新从内存获取数据),防止编译器过度优化
cpu处理一个数据的过程时从内存中将数据加载到寄存器上进行处理
gcc编译器,在编译程序的时候,如果使用了代码优化 -Olevel选项,发现某个变量使用频率非常高,为了提高效率,则直接将变量的值设为某个寄存器的值,以后访问的时候直接从寄存器访问,则减少了内存访问的过程提高了效率
但是这种优化有时候会造成代码的逻辑混乱
因此使用volatile关键字修饰变量,让cpu无论如何每次都重新到内存中获取数据

函数的可重入与不可重入:
函数的重入:在多个执行流程中,同时进入一个函数运行
函数可重入:指的是函数重入之后,不会造成数据二义或者逻辑混乱
函数不可重入:指的是函数重入之后,有可能会造成数据二义或者逻辑混乱
函数是否可重入的判断基准:这个函数中是否对全局变量进行了非原子的操作;
操作的原子性:操作一次完成,中间不会被打断
原子操作:操作要么一次完成,要么就不做

一个函数若根本就没有操作全局数据,则可以是可重入的,因为每个函数调用的时候都有独立的函数栈
一个函数若对全局数据进行了操作,但是操作是原子性的,则也是可重入的;
以后我们实现函数的时候,或者使用别人的函数的时候,最好能够考虑一下是否可重入的问题,防止使用的时候出现问题

总结

信号:
信号是什么?有什么用?
linux信号有多少种?分为哪几类?
信号的生命周期:内核中的生命周期是什么样子?
如何产生信号?
如何让进程知道自己收到了某个信号?
如何删除信号的痕迹?
如何处理信号的?信号的处理方式又有哪些?如何修改信号的处理方式呢?
信号阻塞是在干什么?如何阻塞一个信号?
信号的应用:SIGPIPE/SIGCHLD
volatile关键字是干什么的?
编写函数的时候注意函数的可重入与不可重入情况?什么是函数的可重入与不可重入?
编写函数的时候注意函数的可重入与不可重入情况?什么是函数的可重入与不可重入?
IPC:
进程间通信是什么?为什么要提供进程间通信方式?
进程间通信方式有哪几种?
各自的本质原理是什么?
他们的特性又有哪些?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值