信号

首先,信号量与信号是完全不同的两个概念

进程信号
理解

作用:操作系统通知进程发生某事件,需打断当前进程去处理该事件。相当于软件中断
事件是多种多样的,因此信号也是多种多样的。
kill命令:

查看操作系统中所有定义好的信号种类:kill -l

用户能看到并使用的有64种,可以分别为:

  • 1-31号【非可靠信号】:每个信号有具体对应事件
  • 34-64号【可靠信号】:在操作系统中没有具体事件,命名草率

SIGCHLD:子进程退出后,OS发送给父进程的通知信号
默认忽略处理:子进程不被等待会成为僵尸进程(因为父进程没有关注);父进程一直等待才能避免产生僵尸进程
修改信号的处理方式之后:在信号到来时,进程自动回调信号回调函数,在回调函数重调用进程等待接口处理子进程的退出
非可靠信号:若同时退出多个子进程,有可能会造成事件丢失;因此回调函数中循环进行进程等待,直到没有子进程退出
sigcb(int signo) { while(waitpid(-1, NULL,WNOHANG)> 0);}

信号生命周期

信号的产生、信号在进程中注册、信号在进程中注销、处理信号

信号的产生

对于硬件ctrl+c、ctrl+z。软件上:
命令:kill -signum pid
kill命令能杀死一个进程。是因为kill命令功能是向进程发送信号【默认发送15号终止信号】
函数

int kill(pid_t pid,int sig)
//向指定进程发送指定信号
int raise(int sig)
//向调用进程自己发送指定信号
void abort(void)
//向调用进程自己发送SIGABRT信号
unsigned int alarm(unsigned int seconds)
//seconds秒后向指定进程发送一个SIGALRM信号,告诉进程时间到了


core dump;
#进程退出后,OS保存该进程运行信息,便于后面调试【默认关闭】
ulimit -c 1024
#开启core dump,并将core文件最大大小设为1024kb
gdb ./test  core-file xxx.pid
#(产生的core文件常规gdb调试)
信号在进程中注册

在进程中注册在于让进程知道自己收到了信号。
之前知道进程就是一个pcb,Linux下就是一个task_struct结构体。在pcb结构体中定义了一个信号的集合【位图】
当给进程发送信号时,将该信号对应位置置为1,进程可以通过查看位图判断进程是否有收到信号

pending信号集合【未决信号集合】:未决是一个状态,指的是信号产生了,但是还没有被处理的一个区间状态
这个位图实际上是一个sigset_t{unsigned long int_val[_SIGSET_NWORDSI]}结构体;这个数组被用于实现位图
位图这个信号集合,只能用于标记进程是否收到了这个信号,无法确定这个信号收到了多少次。因此在内核中其实还有一个链表sigqueue{…siginfo_t…}
信号的注册就是组织一个信号的信息,添加到信号链表中,并且将信号pending位图进行重置

非可靠信号的注册:在注册信号时,判断当前信号是否已经注册过(位图是否已经为1) 若没有注册,则添加节点,修改位图;若注册过了,则什么也不干(这种信号在链表中就永远最多只有一个节点后来到达的信号就会被丢弃——事件丢失)

可靠信号的注册:在注册信号时,每次针对新到来的信号都会创建一个节点添加到链表中,并且位图置1; (链表中有可能有多相同节点)

信号在进程中注销

抹除信号存在痕迹
非可靠信号:一旦删除,置为0【信号只注册一次,最多只有一个节点】
可靠信号:删除后判断是否有其他相同节点,若没有置为0;若还有信号要处理,位图依然为1。

处理信号

信号的递达
进程处理事件、事件可理解为一功能在程序中功能的实现单位为函数。
进程在收到信号后,针对该信号的事件找到相应函数,调用函数。

信号的处理方式
信号的处理方式最终是进程收到信号后执行信号的回调函数完成功能。

  • 默认处理:系统中定义好的默认函数
  • 忽略处理:依然可以信号注册,但处理动作为什么都不做
  • 自定义处理:由用户自定义的信号回调函数替换原来的信号处理动作中的回调函数

修改信号处理方式:
sighandler_t signal(int signum,sighandler_t handler);
sighandler_t:typedef void(*sighandler_t)(int)

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

  1. 程序运行在用户态主控流程,在中断/异常/系统调用的情况下,进程切换到内核态运行
  2. 完成内核功能之后,在即将返回用户态之前调用do_signa接口去处理信号
  3. 默认处理/忽略处理都是在内核中完成,但是自定义接口是用户自己定义的函数运行的用户态
  4. 因此进程从内核态切换到用户态运行的是信号自定义回调函数,去处理信号事件
  5. 在信号处理函数运行完毕后,调用sigreturn返回内核态
  6. 当没有信号待处理,则调用sys_sigreturn返回用户态主控流程从之前运行的地方开始继续运行
信号的阻塞

理解:阻止信号被处理(在进程中标记信号,这些信号到来注册之后,暂时不处理,直到解除阻塞)
如何阻塞信号:进程pcb中有一个block信号集合, 将集合中信号相应为置1,就表示要阻塞这个信号了

int sigprocmask(int how, const sigset _t *set, sigset t *oldset);

SIG BLOCK/SIG_ UNBLOCK/SIG_ SETMASK

在所有信号中,有两个信号无法被阻塞,无法被自定义,无法被忽略:

  • 9号——SIGKILL
  • 19号——SIGSTOP

什么情况下进程无法被杀死?
僵尸进程,处于停止状态的进程,信号被阻塞/忽略处理的进程

函数的可重入&不可重入

函数的重入:多个执行流同时执行进入同一个函数
不可重入函数:函数重入之后有可能造成数据二 义或者逻辑混乱
可重入函数:函数重入之后不会造成数据二义或者逻辑混乱。
函数是否可重入的关键点: 一个函数中是否对一个全局数据进行了不受保护的操作

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值