欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux 信号signal

程序员文章站 2022-07-12 11:17:19
...

1. 信号的基本概念

    联系现实生活中的信号,我们可以理解为:Linux中的signal其实就是一种标志,操作系统知道这个标志代表着什么含义,以及知道遇见这个标志它应该采取怎样的动作。(如红灯信号,你知道红灯信号代表着不能通过马路,而你采取的动作就是等待)

1.1 信号的分类:

使用kill -l : 可以查看系统定义的信号列表。

Linux 信号signal

总共有62种信号。1-31号信号称为普通信号,34-64号信号称为实时信号。

每个信号都有一个编号和一个宏定义的名称,这些宏定义可以在/usr/include/signal.h中找到。

以1号信号为例,它的宏定义为:#define SIGHUP 1

1.2 信号的常见处理方式
  • 忽略信号
  • 执行默认的信号处理动作
  • 捕捉信号。提供一个信号处理函数,要求内核在处理信号时切换至用户态执行这个处理函数

2. 产生信号

信号通过以下三种方式产生,下面分别进行介绍:

2.1 通过终端按键产生信号

用户在终端按下某些键的时候,终端驱动程序会发送信号给前台进程。比如:按下Ctrl-c会产生SIGINT信号,SIGINT信号的默认处理动作是终止进程;按下Ctrl-\ 会产生SIGQUIT信号,SIGQUIT的默认处理动作是终止进程并且Core Dump ; 按下Ctrl-z 会产生SIGSTP信号,SIGSTP信号可以使前台进程停止。

什么是 Core Dump?

当一个进程要异常终止时,可以选择把进程的用户空间中的内存数据全部保存到磁盘上,文件名通常是core,这个过程就叫做core dump。

进程异常终止通常是因为有bug,事后可以用调试器检查core文件以查清错误原因,这就叫做Post-mortem Debug(事后调试)。

core文件的大小?

一个进程允许产生多大的core文件取决于进程的Resource Limit(该信息通常保存在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit 命令来改变这个限制,使之允许产生core文件。

使用ulimit -a 来查看系统中某些文件的大小。

Linux 信号signal

Linux 信号signal

2.2 调用系统函数向进程发信号
  • kill命令。kill命令是调用kill函数实现的,kill函数可以给一个指定的进程发送指定的信号。例如:kill -2 4980  给4980号进程发送一个2号信号(即SIGINT信号)
  • raise函数可以给当前进程发送指定的信号(自己给自己发信号)
  • abort函数可以使当前进程接受到信号而异常终止

函数说明:

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
参数:
   pid :进程的进程ID 
   signo :信号的编号
返回值:
成功返回0,错误返回 -1

一个简单的例子:子进程循环5次后,休眠10秒,收到SIGINT信号,退出进程。

Linux 信号signal

Linux 信号signal


#include <stdlib.h>
void abort(void);
像exit函数一样,abort函数总会成功,没有返回值。
2.3 由软件条件产生信号

通过alarm函数:调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给进程发SIGALRM信号,该信号的默认动作是终止当前进程。

#include <unistd.h>
unsigned int alarm (unsigned int seconds);

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。返回0,表示这个闹钟成功的响了。

为什么会返回以前设定的闹钟时间还余下的秒数呢?可以这样理解:

小明要睡觉,他定了一个60分钟后响的闹钟,结果他在45分钟的时候就醒了,有两种情况:

  • 小明不想睡了,他把这个闹钟关了,于是alarm(0) 让seconds为0,表示取消以前设定的闹钟,函数的返回值是以前设定的闹钟时间还余下的秒数。
  • 小明还想再睡20分钟,于是他重新设定闹钟为20分钟后响,则以前的闹钟返回的就是以前设定的时间还余下的秒数。

一个闹钟的使用例子:1秒之内,count一直计数,1秒后alarm函数给进程发送SIGALRM信号,终止当前进程。

Linux 信号signal


3. 阻塞信号

3.1 信号的几种状态

信号递达(delivery):实际执行信号的处理动作

信号未决(pending):信号从产生到递达之间的状态

进程可以选择阻塞某个信号,被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达动作。

注意:阻塞和忽略的区别。只要信号被阻塞,那么就不会递达;而忽略是信号在递达后采取的动作。

3.2 信号在内核中的表示

怎么知道操作系统是否给进程发送了信号?

用一个位图来表示31种信号,每一个比特位的位置决定了信号的编号,比特位的内容(0或1)表示收到还是没有收到信号。

例如:第五个比特位为1,表示进程收到了5号信号。PCB中必定包含一个 int signal 字段(位图)。

因此站在操作系统的角度上,操作系统给进程发送了一个信号,就是操作系统修改了该进程PCB中的signal位图的第五个比特位,将0改为1,就说明发送了一个信号。

怎么理解 kill -9 7890 命令?

用kill命令给进程号为7890的进程发送9号信号(SIGKILL)。kill命令是操作系统或shell提供的,底层会调用kill系统调用函数。

kill -9 7890 是操作系统找到7890号进程,把这个进程的PCB中的signal位图的第9个比特位由0置为1.






相关标签: 信号 signal