开发SNMP的时候用到了Linux信号机制,总结了一下关于信号的知识。

信号是一种进程间通信手段,本质是一种软件中断,用来处理异步事件。信号机制是Unix家族里一个古老的通信机制。传统的信号机制有一些弊端,更为严重的是信号处理函数的执行流和正常的执行流同时存在,这可能会对软件运行带来一定问题。


目录

1. 信号的生命周期

2. 信号的产生

3. 信号的处理

4. 信号的分类

5. 信号的可靠性


1. 信号的生命周期

当向目标进程发送一枚信号SIGXXX时,Linux内核收到了产生的信号,然后再目标进程的进程描述符里记录了一笔:收到了信号SIGXXX,但是还没有递送给目标进程的这一段时间里,信号处于挂起状态,被称为( pending )信号,也称为未决信号。内核将信号递送给进程,进程就会暂停当前的控制流,转而去执行信号处理函数,这就是一个信号的完整生命周期。

典型信号可以会按照上面所述流程来处理,但是实际情况要复杂的多,还有许多场景需要考虑:

  • 目标进程正在执行关键代码,不能被信号中断,需要阻塞某些信号,那么在这期间,信号就不允许被递送到进程,直到目标进程接触阻塞。

  • 内核发现同一个信号已经存在,那么它该如何处理这种重复的信号,排队还是丢弃?

  • 内核递送信号的时候,发现已有多个不同的信号被挂起,那它应该优先递送哪个信号?

  • 对于多线程的进程,如果向该进程发送信号,应该由哪一个线程来负责响应?

上述场景都是使用信号前需要考虑的问题。

2. 信号的产生

作为进程间通信的一种手段,进程之间可以互相发送信号,然而通常发给进程的信号,通常源于内核,包括:硬件异常、终端相关的信号和软件事件相关的信号。

1. 硬件异常相关的信号:

信号        信号值                     说明
SIGBUS   |    7            | 总线错误,表示发生了内存访问错误
SIGFPE   |    8            | 表示发生了算术错误
SIGILL   |    9            | 进程尝试执行非法的机器语言指令
SIGSEGV  |    11           | 段错误,表示应用程序访问了无效地址这四种硬件异常,一般是由程序自身引发的,不是由其他进程发送的信号引发的,并且这些异常都比较致命,以至于进程无法继续下去,所以这些信号产生之后,会立即递送给进程。默认情况下,这四种信号都会使进程终止,并且产生core dump文件以供调试。对于这些信号,进程既不能忽略,也不能阻塞。

2. 终端相关的信号

终端定义了如下几种信号生成字符:
Ctrl+C : 产生SIGINT信号
Ctrl+\ : 产生SIGQUIT信号
Ctrl+Z : 产生SIGTSTP信号
键入这些信号生成字符,相当于向前台进程组发送了对应的信号。另一个和终端关系比较密切的信号是SIGHUP信号。很多程序员都遇到过这种问题:使用ssh登陆到远程的Linux服务器,执行比较耗时的操作(如编译项目代码),却因为网络不稳定,或者需要关机回家,ssh连接被断开,最终导致操作中途被放弃而失败。之所以会这样,是因为一个控制进程在失去其终端之后,内核会负责向其发送一个SIGHUP信号。在登录会话中,shell通常是终端的控制进程,控制进程收到SIGHUP信号后,会引发如下的连锁反应:shell收到SIGHUP后会终止,但是在终止之前,会向由shell创建的前台进程组和后台进程组发送SIGHUP信号,为了防止处于停止状态的任务接收不到SIGHUP信号,通常会在SIGHUP信号之后,发送SIGCONT信号,唤醒处于停止状态的任务。前台进程组和后台进程组的进程收到SIGHUP信号,默认的行为是终止进程,这也是前面提到的耗时任务中途失败的原因。注意,单纯地将命令放入后台执行(通过&符号),并不能摆脱被SIGHUP信号追杀的命运。

3. 软件事件相关的信号

软件事件触发信号产生的情况比较多:
1. 子进程退出,内核可能会向父进程发送SIGCHLD信号
2. 父进程退出,内核可能会给子进程发送信号
3. 定时器到期,给进程发送信号。

3. 信号的处理

从上面可以看到,信号产生的源头有很多,那么内核将信号递送给进程后,进程会执行什么操作呢?

很多信号尤其是传统的信号,都会有默认的信号处理方式,如果我们不改变信号的处理函数,那么收到信号之后,就会执行默认的操作。信号的默认操作有一下几种:

1. ignore : 显示地忽略信号,内核将会丢弃该信号,信号不会对目标进程产生任何影响。2. terminate : 终止进程,很多信号的默认处理是终止进程。3. core : 生成核心转储文件并终止进程,进程会被杀死并且产生核心转储文件。核心转储文件记录了进程死亡现场的信息,用户可以使用核心转储文件来调试,分析进程死亡的原因。4. stop : 停止进程不同于终止进程,终止进程是进程已经死亡,但是停止进程仅是使进程暂停,将进程的状态设置成TASK_STOPPED,一旦收到恢复执行的信号,进程还可以继续执行。5. continue : 恢复进程的执行,和停止进程相对应,某些信号可以使进程恢复执行。根据信号的默认处理,可以将传统信号进行如下分类:1. ignore类别
-----------------------------------------------------------
|   信号     |  值  |                   说明                |
-----------------------------------------------------------
|  SIGCHLD  |   17 |  子进程终止、停止或恢复执行              |
-----------------------------------------------------------
|  SIGURG   |   23 | 套接字上的紧急数据                      |
-----------------------------------------------------------
|  SIGWINCH |   28 | 终端窗口大小发生变化                    |
-----------------------------------------------------------2. terminate类别
-----------------------------------------------------------
|   信号     |  值  |                   说明                |
-----------------------------------------------------------
|  SIGHUP    |  1  | 挂起(hangup),多用于终端断开
-----------------------------------------------------------
|  SIGINT    |  2  | 终端中断
-----------------------------------------------------------
|  SIGKILL   |  9  | 杀死进程,该信号不能被忽略、屏蔽,该信号处
|            |     | 理函数也不能被用户自定义函数该别
-----------------------------------------------------------
|  SIGUSR1   |  10 | 用户自定义信号1
-----------------------------------------------------------
|  SIGUSR2   |  12 | 用户自定义信号2
-----------------------------------------------------------
|  SIGPIPE   |  13 | 管道断开,多见于socket通信
-----------------------------------------------------------
|  SIGALAM   |  14 | 定时器到期,该信号多用于实现定时器
-----------------------------------------------------------
|  SIGTERM   |  15 | 终止进程,因为SIGKILL过于残暴,进程终止时
|            |     |可能需要先执行一些操作来保存现场信息,所以
|            |     |合理的杀死进程的方法是先发送SIGTERM信号,稍
|            |     |等片刻在发送SIGKILL信号
-----------------------------------------------------------
|  SIGSTKFLT |  16 | 协处理器栈错误,Linux并未使用该信号
-----------------------------------------------------------
|  SIGVTALRM |  26 | 虚拟定时器过期,setitimer函数的ITIMER_VIRTUAL模式
-----------------------------------------------------------
|  SIGPROF   |  27 | 性能分析定时器过期,setitimer函数的ITIMER_PROF模式
-----------------------------------------------------------
|  SIGIO     |  29 | I/O时可能发生
-----------------------------------------------------------
|  SIGPWR    |  30 | 电量将要耗尽
-----------------------------------------------------------3. core类别
-----------------------------------------------------------
|   信号     |  值  |                   说明                |
-----------------------------------------------------------
|  SIGQUIT  |   3  |  终端Ctrl+\可产生该信号
-----------------------------------------------------------
|  SIGILL   |   4  | 非法的指令
-----------------------------------------------------------
|  SIGTRAP  |   5  | 跟踪/断点,gdb/strace一类工具会使用该信号,
|           |      | 这类工具会拦截或修改SIGTRAP信号处理函数
-----------------------------------------------------------
|  SIGABRT  |   6  | 进程终止,进程调用abort函数会向自身发送
|           |      | SIGABRT信号,此外如果使用了assert,assert
|           |      | 失败时也会产生SIGABRT信号
-----------------------------------------------------------
|  SIGBUS   |   7  | 总线错误
-----------------------------------------------------------
|  SIGFPE   |   8  | 算术异常
-----------------------------------------------------------
|  SIGSEGV  |   11 | 段错误,访问了非法的地址
-----------------------------------------------------------
|  SIGXCPU  |   14 | 突破了对CPU时间的限制
-----------------------------------------------------------
|  SIGXFSZ  |   25 | 突破了对文件大小的限制
-----------------------------------------------------------
|  SIGSYS   |   31 | 无效的系统调用
-----------------------------------------------------------4. stop类别
-----------------------------------------------------------
|   信号     |  值  |                   说明                |
-----------------------------------------------------------
|  SIGSTOP  |   19 |  确保进程会停止,该信号不能被忽略,不能将信号
|           |      |信号处理函数改写成用户指定的函数
-----------------------------------------------------------
|  SIGTSTP  |   20 | 终端停止信号,和SIGSTOP功能类似,但是可以被
|           |      |进程忽略,可以被捕捉执行用户指定的信号处理函数
-----------------------------------------------------------
|  SIGTTIN  |   21 | 用于作业控制,如果后台进程组尝试对终端执行
|           |      | read操作,终端驱动程序就会向该进程组发送
|           |      |SIGTTIN信号
-----------------------------------------------------------
|  SIGTTOU  |   22 | 如果终端启动了TOSTOP(如通过stty tostop命令)
|           |      | 即不允许后台进程向终端写入,而某一后台进程
|           |      | 尝试写入终端时,终端驱动程序就会向进程组发送
|           |      | SIGTTOU信号
-----------------------------------------------------------5. continue类别
-----------------------------------------------------------
|   信号     |  值  |                   说明                |
-----------------------------------------------------------
|  SIGCONT  |   18 |  如果目标进程处于停止状态,则恢复执行
-----------------------------------------------------------

4. 信号的分类

在Linux的shell终端,执行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上面并没有列出32号信号和33号信号,这两个信号(SIGCANCEL 和 SIGSETXID)被NPTL这个线程库征用了,
用来实现线程的取消。从内核层来说,32号信号应该是最小的实时信号(SIGRTMIN),但是由于32号和33号
被glibc内部征用了,所以glibc将SIGRTMIN设置成了34号信号。

5. 信号的可靠性

信号可以分为两类:

  • 可靠信号 :信号值在[ 1, 31 ]之间的所有信号,被称为不可靠信号;
  • 不可靠信号 :在[ SIGRTMIN, SIGRTMAX]之间的信号被称为可靠信号;

不可靠信号是指发送的信号,内核不一定能递送给目标进程,信号可能会丢失。因为不可靠信号出现较早且应用广泛,处于兼容性考虑,不能改变这些信号的行为模式,所以只能新增信号。新增的信号就是[SIGRTMIN, SIGRTMAX]范围内的信号,它们被称为可靠信号。

可靠信号和不可靠信号的根本差异在于收到信号后,内核有不同的处理方式。

对于不可靠信号,内核用位图来记录该信号是否处于挂起状态。如果收到某不可靠信号,内核发现已经存在该信号处于未决状态,就会简单地丢弃该信号。因此发送不可靠信号,信号可能会丢失,即内核递送给目标进程的次数,可能小于信号发送的次数。

对于可靠信号,内核内部有队列来维护,如果收到可靠信号,内核会将信号挂到相应的队列中,因此不会丢弃。严格手来,内核也设有上限,挂起信号的个数也不能无限制地增大,不然耗费内核资源,因此只能说,在一定范围之内,可靠信号不会被丢弃。

可以通过如下命令获取内核对挂起信号的限制值,不同的系统会有不一样的值

ulimit -a

从下图可以看到,信号挂起队列的限制值是7713

参考资料:

1. man signal http://www.man7.org/linux/man-pages/man7/signal.7.html

2. 《Linux环境编程 从应用到内核》高峰,李彬

Linux信号 一 信号可靠性与分类相关推荐

  1. Linux异步之信号(signal)机制分析

    From:http://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html From:http://kenby.iteye.com/blog/11 ...

  2. linux 之进程信号

    1       信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的. ...

  3. 【B站视频笔记】linux 进程间通信(ipc)信号(软中断信号)signal库函数、可靠信号和不可靠信号、信号集sigprocmask(信号掩码、信号递达Delivery、信号未决Pending)

    [视频教程]Linux信号详解(可靠信号.不可靠信号.阻塞信号.信号处理函数) [博文]Linux信号 文章目录 背景 课程笔记 一.如何让程序在后台运行 1.加"&"符号 ...

  4. Linux中的信号是什么?

    什么是信号? 操作系统信号,英文signal,简称信号. 是IPC中唯一一种异步的通信方法. 它的本质是用软件来模拟硬件的中断机制. 信号用来通知某个进程有某个事件发生了.例如,在命令行终端按下某些快 ...

  5. Linux进程间通信之信号

    一.信号 1.信号本质 信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的,信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进 ...

  6. linux查看wifi信号命令_无线信号强度解析及linux如何查看wifi信号强弱等

    dBdB是一个表征相对值的值,纯粹的比值,只表示两个量的相对大小关系,没有单位,当考虑甲的功率相比于乙功率大或小多少个dB时,按下面的计算公式:10log(甲功率/乙功率),如果采用两者的电压比计算, ...

  7. Linux下Signal信号

    信号是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念. Linux对信号机制的大致实现方法.如何使用信号,以及有关信号的几个系统调 用.    信号机制是进程之间相互传递消息的一种方 ...

  8. linux内核定义的常用信号6,Linux中的信号

    在 Linux 中,理解信号的概念是非常重要的.这是因为,信号被用于通过 Linux 命令行所做的一些常见活动中.例如,每当你按 Ctrl+C 组合键来从命令行终结一个命令的执行,你就使用了信号.每当 ...

  9. linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

最新文章

  1. svn的代码提交到git服务器_svn服务器代码仓库,数据迁移到git仓库
  2. ASP.NET Web API自身对CORS的支持:从实例开始
  3. bzoj1010[HNOI2008]玩具装箱toy 斜率优化dp
  4. PostgreSQL 13隐藏杀手锏特性
  5. 【数论】—— 多边形数的计算(三角形数,五边形数)
  6. ORB-SLAM3 代码解读
  7. 通过VBA实现FTP自动下载及关键字检索等功能
  8. c语言作业汽车加速,C语言求车速
  9. 解读 | 关于阿里巴巴架构大调整,有 7 个重点值得特别关注
  10. AMD Fluid Motion Video补帧教程
  11. Ajax读取本地html文件
  12. linux给文件夹添加查看密码是什么,Linux如何给文件夹设置密码
  13. java 快递打印_基于java的快递打印系统
  14. 哈佛大学各学院成立发展历史沿革介绍及整体评价
  15. [SP]梦网masterSP模式下的sp生存
  16. 手把手教你如何做自媒体赚钱,揭开自媒体赚钱真相!记得收藏
  17. 互联网思维方式(一)
  18. 为什么HikariCP是性能最好的数据库连接池?
  19. 高中毕业,暑假想学习一下编程知识,该怎么学习
  20. 如何修复损坏的硬盘分区

热门文章

  1. 写在那个毕业五年的日子
  2. NSLayoutConstraint
  3. 网页制作中最有用的免费Ajax和JavaScript代码库
  4. Go Web开发之Revel - 组织结构
  5. 基于MDA的移动应用开发建模及实现
  6. python怎么把图片压缩_使用Python轻松批量压缩图片
  7. python写一个类方法_Python基础|类方法的强制重写与禁止重写
  8. 形态数轴上的反密码子和氨基酸
  9. 游戏开发需要具备哪些技术_生鲜小程序需要具备哪些功能板块?生鲜小程序开发...
  10. 24小时临时邮箱_免费临时邮箱和接码平台