信号
信号
1.基本概念
信号是事件发生时对进程的通知机制,也可以把它称为软件中断。信号与硬件中断的相似之处在于能够打断程序当前执行的正常流程, 其实是在软件层次上对中断机制的一种模拟。 大多数情况下,是无法预测信号达到的准确时间,所以,信号提供了一种处理异步事件的方法
1.1信号的用途
一个有“一定权限”的进程(比如内核)可以给另一个进程发送信号,所以信号是一种进程间通信的机制。当某个事件发生时,一个进程通知另一个进程。
1.2信号的使用案例
- Linux在终端中输入
Ctrl + Z
可以使内核发送**暂停信号 **(SIGCONT
)以暂停前台的进程 - Linux在终端中输入
Ctrl + C
可以使内核发送中断信号(SIGINT
)以结束前台的进程 - 用户可以通过
kill()
系统调用将任意信号发送给其它进程。当然对此是有所限制的,接收信号的进程和发送信号的进程的所有者必须相同,亦或者发送信号的进程的所有者是 root 用户 - 硬件发生异常,即硬件检测到错误条件并通知内核,随即再由内核发送相应的信号给相关进程
前台进程:当用终端运行程序时,该进程会占用终端,即为一个前台进程。如果一个进程在后台运行,没占用终端,那他就不算前台进程。
1.3对信号的处理
- 忽略信号
在信号到达后,不去处理,就像没有一样。但SIGCONT
和SIGINT
这2个信号不能忽略,因为它们向内核和root提供了使进程终止或停止的可靠方法
- 捕获信号
可以使用signal()
系统调用为信号注册一个处理函数,在进程捕获到该信号后会调用这个函数(与Qt的信号槽类似)
- 执行系统的默认操作
操作系统为每个信号都实现了一个默认的处理函数,对于大多数信号,系统的默认处理函数就是终止
1.4信号在Linux中的实现
信号在Linux中实际上就是个int
型变量,下面列出部分信号的序号
1 | /* Signals. */ |
2.信号的分类
(1)信号根据其可靠性可以分为:可靠信号和不可靠信号。
- 不可靠信号:最早被提出来的信号,无法排队处理,可能处理错误或丢失
- 可靠信号:支持排队,不会丢失的信号
(2)信号还可以分为:实时信号和非实时信号
- 实时信号都是可靠的
- 非实时信号都是不可靠的
3.信号的处理函数
Linux中,可以通过siganl()
或者sigaction()
为某个信号指定其对应的处理函数,就相当于Qt里的槽函数。
4.发送信号
进程中将信号发送给另一个进程是需要权限的,并不是可以随便给任何一个进程发送信号,超级用户root 进程可以将信号发送给任何进程,但对于非超级用户(普通用户)进程来说,其基本规则是发送者进程的实际用户 ID 或有效用户 ID 必须等于接收者进程的实际用户 ID 或有效用户 ID。
4.1kill()系统调用
kill()
系统调用的原型如下:
1 |
|
它可以将任意信号发给某个进程
4.2raise()系统调用
raise()
系统调用的原型如下:
1 |
|
raise()
用于向自己发送信号,等价于kill(getpid(),sig_num);
5.信号集
信号集是一个能够表示多个信号的数据结构,其定义如下:
1 |
|
使用这个结构体可以表示一组信号,将多个信号添加到该数据结构中, 当然 Linux 系统了用于操作sigset_t
信号集的 API,譬如 sigemptyset()
、 sigfillset()
、 sigaddset()
、 sigdelset()
、 sigismember()
6.信号掩码
信号掩码是一个信号集,用于阻塞某些信号传递给该进程,就像Qt中的事件过滤器一样