Skip to content

信号简介

信号是信息的载体,Linux/UNIX 环境下,古老、经典的通信方式, 现下依然是主要的通信手段。 信号在我们的生活中随处可见,例如:

  • 古代战争中摔杯为号;
  • 现代战争中的信号弹;
  • 体育比赛中使用的信号枪......

信号的特点

  • 简单
  • 不能携带大量信息
  • 满足某个特点条件才会产生

信号的机制

进程A给进程B发送信号,进程B收到信号之前执行自己的代码,收到信号后,不管执行到程序的什么位置,都要暂停运行,去处理信号,处理完毕后再继续执行。与硬件中断类似——异步模式。但信号是软件层面上实现的中断,早期常被称为“软中断”。

每个进程收到的所有信号,都是由内核负责发送的。 进程A给进程B发送信号示意图:

信号的状态

信号有三种状态:产生、未决和递达。

信号的产生

  • 按键产生,如:Ctrl+c、Ctrl+z、Ctrl+\
  • 系统调用产生,如:kill、raise、abort
  • 软件条件产生,如:定时器alarm
  • 硬件异常产生,如:非法访问内存(段错误)、除0(浮点数例外)、内存对齐出错(总线错误)
  • 命令产生,如:kill命令

未决

  • 产生和递达之间的状态。主要由于阻塞(屏蔽)导致该状态。

递达

  • 递送并且到达进程。

信号的处理方式

  • 执行默认动作
  • 忽略信号(丢弃不处理)
  • 捕捉信号(调用用户的自定义的处理函数)

信号的特质

信号的实现手段导致信号有很强的延时性,但对于用户来说,时间非常短,不易察觉。

Linux内核的进程控制块PCB是一个结构体,task_struct,除了包含进程id,状态,工作目录,用户id,组id,文件描述符表,还包含了信号相关的信息,主要指阻塞信号集和未决信号集

注:表示PCB的task_struct结构体定义在:/usr/src/linux-headers-4.4.0-97/include/linux/sched.h:1390

信号的四要素

通过 man 7 signal 可以查看信号相关信息

信号的编号

  • 使用 kill -l 命令可以查看当前系统有哪些信号,不存在编号为0的信号。其中1-31号信号称之为常规信号(也叫普通信号或标准信号),34-64称之为实时信号,驱动编程与硬件相关。
bash
$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX

信号的默认处理动作

  • Term:默认作是终止进程。
  • Ign:默认作是忽略该信号。
  • Core:默认作是终止进程并转储核心,生成Core文件。(查验死亡原因,用于gdb调试)
  • Stop:默认作是停止进程。
  • Cont:默认作是继续该过程(如果当前已停止)。

特别需要注意的是:The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.

信号的名称

signalstandardactioncomment
SIGHUP1Term终端挂起或者控制进程终止
SIGINT2Term键盘中断(Ctrl+c)
SIGQUIT3Core键盘退出(Ctrl+)
SIGILL4Core非法指令
SIGTRAP5Core断点异常
SIGABRT6Core由abort(3)发出的退出指令
SIGBUS7Core总线错误
SIGFPE8Core浮点运算错误
SIGKILL9Term无条件终止进程
SIGUSR110Term用户保留
SIGSEGV11Core无效内存引用
SIGUSR212Term用户保留
SIGPIPE13Term消息管道损坏
SIGALRM14Term定时器超时
SIGTERM15Term软件终止
SIGSTKFLT16Core协处理器堆栈错误
SIGCHLD17Ign子进程状态改变
SIGCONT18Cont如果进程已停止,则使其继续
SIGSTOP19Stop非终端停止进程
SIGTSTP20Stop终端停止进程
SIGTTIN21Stop后台进程读终端
SIGTTOU22Stop后台进程写终端
SIGURG23Ign套接字上有紧急数据
SIGXCPU24Core进程执行时间超过限制
SIGXFSZ25Core文件长度超过限制
SIGVTALRM26Term虚拟定时器超时
SIGPROF27Term组定时器超时
SIGWINCH28Ign窗口大小改变
SIGIO29Term描述符上可以进行I/O操作
SIGPWR30Term电源故障
SIGSYS31Core非法系统调用

产生信号的事件

几个常用到的信号

SIGINT、SIGQUIT、SIGKILL、SIGSEGV、SIGUSR1、SIGUSR2、SIGPIPE、SIGALRM、SIGTERM、SIGCHLD、SIGSTOP、SIGCONT

信号集

Linux内核的进程控制块PCB是一个结构体,这个结构体里面包含了信号相关的信息,主要有阻塞信号集和未决信号集。

阻塞信号集和未决信号集

  • 阻塞信号集中保存的都是被当前进程阻塞的信号。若当前进程收到的是阻塞信号集中的某些信号,这些信号需要暂时被阻塞,不予处理。
  • 信号产生后由于某些原因(主要是阻塞)不能抵达,这类信号的集合称之为未决信号集。在屏蔽解除前,信号一直处于未决状态;若是信号从阻塞信号集中解除阻塞,则该信号会被处理,并从未决信号集中去除。

阻塞信号集是当前进程要阻塞的信号的集合,未决信号集是当前进程中还处于未决状态的信号的集合,这两个集合存储在内核的PCB中。

下面以SIGINT为例说明信号未决信号集和阻塞信号集的关系:

  • 当进程收到一个SIGINT信号(信号编号为2),首先这个信号会保存在未决信号集合中,此时对应的2号编号的这个位置上置为1,表示处于未决状态;在这个信号需要被处理之前首先要在阻塞信号集中的编号为2的位置上去检查该值是否为1:
    • 如果为1,表示SIGNIT信号被当前进程阻塞了,这个信号暂时不被处理,所以未决信号集上该位置上的值保持为1,表示该信号处于未决状态;
    • 如果为0,表示SIGINT信号没有被当前进程阻塞,这个信号需要被处理,内核会对SIGINT信号进行处理(执行默认动作,忽略或者执行用户自定义的信号处理函数),并将未决信号集中编号为2的位置上将1变为0,表示该信号已经处理了,这个时间非常短暂,用户感知不到。
  • 当SIGINT信号从阻塞信号集中解除阻塞之后,该信号就会被处理。