linux中的信号


一、信号概念

在这里插入图片描述

是一种事件通知机制,通知进程发生了某个事件,打断进程当前的操作然后去处理这个事件。

种类: kill -l 查看linux中的信号种类—62种

非可靠/非实时信号:1-31
可靠/实时信号:34-64

二、生命周期

1、信号的产生

kill -signum pid 命令

kill杀死一个进程原理:给进程发送一个能让进程退出的信号。

int kill(pid_t pid, int sig); 给指定进程发送指定信号;

int raise(int sig); 给自己发送指定的信号;

void abort(void); 给自己发送sigabrt信号;

unsigned int alarm(unsigned int s); s秒后发送sigalrm信号给自己。

硬件: ctrl+c - 2; ctrl+\ - 3; ctrl+z – 20

2、信号的注册

让进程知道自己收到了某个信号/事件需要处理,在进程中做标记。

在pcb中有个未决信号集合(位图),用于标记进程信号。

(1)非可靠信号的注册

 1-31号信号若没有注册过则注册,
 已注册则什么都不做(信号丢弃)。
  (不会同时注册第二次).

(2)可靠信号的注册

  34-64号信号不管是否注册,位图置1,
  向sigqueue链表加一个节点。

3、信号的注销

删除待处理的未决信号(pending位图中)

一个是位图,另一个是链表:

  • 位图:主要是为了标记是否收到了某个信号
  • 链表:统计收到多少个相同信号

(1)非可靠信号注销

因为非可靠信号不会重复注册,链表中最多只有一个节点,
因此删除一个节点,并且对应位图置0。

(2)可靠信号的注销

因为可靠信号有可能存在多个相同信号节点,
因此删除一个节点后,若还有相同节点则位图不变,否则位图置0。

4、信号的处理

运行信号的处理函数(每个信号的处理函数不同)

信号的处理函数(处理方式)是可以修改

处理方式种类:

(1)默认处理

系统中针对每个信号定义好的处理方式.

(2)忽略处理

收到了信号处理方式就是忽略.

(3)自定义处理

用户自定义信号处理函数然后进行替换.

sighandler_t signal(int signum, sighandler_t handler);
    signum:要修改处理方式的信号的值
    handler:函数指针   SIG_DFL-默认/SIG_IGN-忽略
       typedef void(*sighandler_t)(int);

自定义处理方式的信号捕捉流程

  • 一个用户进程无法直接访问内核空间,只能通过系统调用进行访问,当程序通过系统调用访问内核空间的过程称之为运行在内核态
    在这里插入图片描述
    (1) 程序运行因为中断\异常\系统调用从用户态切换到内核态.
    (2) 完成内核处理功能后,在返回用户态主控流程之前检测是否有信号待处理,有则处理信号.
    (3) 默认和忽略在内核中完成,自定义需要到用户态运行.
    (4) 信号的自定义处理函数运行完毕,返回内核态.

5、信号的阻塞

阻止当前未决信号的处理
(有信号注册了但当前不处理,等到解除阻塞之后再处理)

在pcb中,标记哪些信号来了但是暂不处理

block阻塞信号集合:

  • 添加了哪个信号,则表示该信号来了暂不处理.

接口:

int sigprocmask(int how,sigset_t *new,sigset_t *old);
功能:对调用进程的阻塞信号集合进行操作。
  how:
      SIG_BLOCK     block |=new;  向block集合添加new信号
      SIG_UNBLOCK   block &=new;从block中移除new信号
      SIG_SETMASK   block = new;new设置为block
  new:要添加/移除阻塞的信号集合;
  old:用于接收修改前block中的信号(多数用于还原)

示例:

1.先修改指定信号的处理方式   signal(sig,handler)
2.阻塞指定的/所有信号    sigprocmask(SIG_BLOCK)
3.等待用户按下回车       getchar()
4.解除阻塞              sigprocmask(SIG_UNBLOCK)
sigset_t new;
sigemptyset(sigset_t *set);清空
sigaddset(sigset_t *set, int sig);添加指定信号到集合
sigfillset(sigset_t *set);添加所有信号到集合中
sigdelset(sigset_t *set, int sig);从集合中移除指定信号
sigismember(sigset_t *set, int sig);判断信号是否在集合中

在进程中,有两个信号是不可被阻塞,不可被修改处理方式的:
SIGKILL 、 SIGSTOP

(1)一个进程kill杀不死原因是什么?

  1. 僵尸进程
  2. 信号被修改处理方式
  3. 信号被阻塞

(2)应用

  1. 僵尸进程的处理- -进程等待

子进程退出后,父进程为什么不关心子进程退出状态?

本质:子进程退出后给父进程发送了一个信号-SIGCHLD,
然而SIGCHLD信号的默认方式为忽略,
相当于父进程实际收到了通知但是什么都没做。

sigcb(){while(waitpid(-1,NULL,WNOHANG)>0);}//默认忽略 

signal(SIGCHLD,SIG_IGN);//用户的显示忽略
  1. 所有管道读端被关闭则write触发异常- -SIGIPE

三、关键字volatile

作用

用于修饰变量,保持变量内存可见性
防止编译器过度优化;
cpu处理数据时,总是保证重新从内存中加载数据进行处理

四、函数的可重入与不可重入

1. 函数的重入

一个函数在不同执行流程中同时进入执行

  1. 可重入函数:函数重入后不会造成逾期之外的结果。
  2. 不可重入函数:函数重入后可能出现逾期之外的结果。

2.函数是否可重入的判断基准点

一个函数内部如果对全局数据进行了不受保护的非原子操作,
则该函数为不可重入函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值