7.Linux信号(半成品)

目录

什么是信号?

技术层面的信号

信号保存

阻塞信号

捕捉信号(什么是合适的时候)


什么是信号?

实际生活中的信号就好像是一条条信息,时间到了响了的闹钟,到饭点肚子咕咕的叫声,这些都是信号,告诉你该做某事了。

但信号不一定会立马执行,实际上你可能闹钟响了十分钟后,才醒来。肚子叫了半小时后才吃饭。而收到信号到执行这段时间叫做时间窗口,时间窗口内,任务并没有执行,而是说"你记住了有个任务要做",“在合适时间会去做”。

时间窗口结束后,就要处理任务,处理方式有三种,1.执行默认动作(比如起床)2.执行自定义动作(比如,伸懒腰)3.忽略任务(继续睡)。

技术层面的信号

那什么是技术层面的信号呢?

比如操作时输入CTRL + C 退出进程,这时CTRL + C 就是信号(下图中的二号信号),输入ls,就是显示当前目录文件,此时ls就是信号。

与生活中的信号类比,人是进程,操作系统是闹钟,声音,信号就是任务。

信号概念:信号是进程之间事件异步通知的一种方式,属于软中断。

kill -l命令可以察看系统定义的信号列表

 共62个,前31个普通信号,后31个实时信号,今天关注前31个

九号信号不能被捕捉

信号处理方式

1. 忽略此信号。
2. 执行该信号的默认处理动作。
3. 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号。

信号产生时

如何产生信号呢?

1. 通过终端按键产生信号——通过键盘产生

2. 调用系统函数向进程发信号——这里介绍三个系统调用函数kill,raise,abort

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1。

kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定
的信号(自己给自己发信号)。

#include <stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值

abort函数使当前进程接收到信号而异常终止。

3. 由软件条件产生信号

alarm(seconds)

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动
作是终止当前进程。

4. 硬件异常产生信号(比较重要)

所有的信号都必须经过操作系统的手发出。

信号保存

位图

 00000000000 ... 00000111   ->32位

比特位的位置,代表的是,是谁   信号的编号

比特位的内容,代表的是,是否   是否受到信号

00100000000 ... 00000000   代表收到三号信号

如何实现:

1.信号是给进程发的,task_struct结构体

struct task_struct{

unsigned  int  sigbitmap = 0;(也就是后文的pending表)

}

2.信号是给操作系统发的,那操作系统如何发送呢?

3.操作系统给进程“发送”信号,实际是给进程写信号。

阻塞信号

 

信号相关概念

实际执行信号的处理动作称为信号递达(Delivery)——抵达有三种
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞 (Block )某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

信号内核中

进程描述时,有三个部分,就是说PCB中,有

block表:信号屏蔽字    记录信号被屏蔽/阻塞信息

是谁?是否?

pending位图  保存信号

bandler数组(函数指针数组)

每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。
如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信号。

信号集操作函数

#include <signal.h>
int sigemptyset(sigset_t *set);  全为0 
int sigfillset(sigset_t *set);  全为1
int sigaddset (sigset_t *set, int signo);向前面集合添加后面信号为1
int sigdelset(sigset_t *set, int signo);向前面集合添加后面信号为0
int sigismember(const sigset_t *set, int signo);判断信号是否在信号集当中

sigprocmask   修改信号屏蔽字

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1

三个how参数

增加SIG_BLOCK

屏蔽SIG_UNBLOCK

覆盖SIG_SETMASK

sigpending

#include <signal.h>
sigpending
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1

 

捕捉信号(什么是合适的时候)

从内核态切换至用户态时,进行相关检查。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学c的长弓狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值