一.信号
信号用于通知一个事件的发生,会打断当前操作,去处理这个事件
前提是必须能识别这个信号
生命周期:产生->注册->注销->处理
种类:非可靠信号:1-31号;可靠信号:34-64号
查看信号种类
kill -l
1.信号的产生:硬件产生,软件产生
硬件产生:ctrl+c/ctrl+|/ctrl+z
软件产生:
kill -signum pid//向进程发送一个signum信号
kill(int pid,int signum)
未决:信号从产生到处理之前所处的状态
2.信号的注册
非可靠信号注册:判断pcb中的pending位图中的相应信号是否已经注册(位图是否已经置1);若未注册,则位图修改为1,向sigqueue链表中添加一个信号节点;若已经注册,则不做任何操作(事件丢失)
可靠信号注册:不管信号是否已经注册,都会向链表中添加一个新的信号节点(不会丢失)
3.信号的注销
非可靠信号注销:节点只有一个,注销就是删除节点,位图置0
可靠信号注销:节点有可能有多个,注销就是删除一个节点,判断链表中是否还有相同信号的节点,若没有则位图置0,否则位图不变,依然需要标记有这个信号要处理
4.信号的处理
当进程的运行从内核态返回用户态的时候,处理信号
信号处理方式:
1)默认处理方式–既定义好的处理方式
2)忽略处理方式–处理动作中什么都没做
3)自定义处理方式–用户自己确定信号如何处理–自定义信号的处理函数替换原有的处理函数
修改信号处理方式:
sighandler_t signal(int signum,sighandler_t handler);
自定义处理方式信号的捕捉流程:
发起系统调用->
程序的运行从用户态切换到内核态->
系统调用功能完成->
do_signal返回用户态之前,判断是否有信号处理->
sigcb()->
信号自定义回调处理完毕,sigreturn返回内核态->
当没有信号待处理,sys_sigreturn返回用户态主控流程
5.信号的阻塞
阻止信号被递达–信号依然可以注册,只是暂时不处理
阻塞信号集合:标记哪些信号暂时不被处理
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how:
SIG_BLOCK:向阻塞集合中加入set集合中的信号block=mask|set
SIG_UNBLOCK:从阻塞集合中移除set集合中的信号block=mask&(~set)
SIG_SETMASK:将set集合的信号设置为阻塞集合block=set
oldset:用于保存修改前,阻塞集合中的信号
在所有信号中,9号信号SIGKILL和19号信号SIGSTOP,无法被阻塞,无法被自定义,无法被忽略
二.可重入函数与不可重入函数
函数的重入:多个执行流程同时执行进入相同的函数
可重入:多个执行流程同时执行进入相同的函数不会造成数据二义性以及代码逻辑混乱
不可重入:多个执行流程同时执行进入相同的函数,有可能造成数据二义性以及代码逻辑混乱
当用户设计或使用一个函数时在多个执行流中,需要考虑函数是否可重入情况
函数可重入和不可重入的关键点:这个函数是否对临界资源(全局数据)进行了非原子操作