嵌入式Linux系统编程 — 6.1 信号的基本概念

目录

1 信号的概念和作用

1.1 什么是信号

1.2 信号的目的

1.3 信号如何处理

2 信号的分类

2.1 可靠信号与不可靠信号

2.2 实时信号与非实时信号

3 常见信号与默认行为

3.1 信号本质上是 int 类型数字编号

3.2 常见信号


1 信号的概念和作用

1.1 什么是信号

信号是一种软件中断机制

在Linux系统中,信号是一种软件中断机制,用于通知进程发生了某些事件。信号可以由操作系统内核、用户或另一个进程发送。信号与硬件中断的相似之处在于能够打断程序当前执行的正常流程, 其实是在软件层次上对中断机制的一种模拟。

信号是异步发生的

信号在Linux系统中是异步发生的,这意味着信号的发送和接收是独立于进程的执行流的。当信号发送给进程时,内核会将信号添加到进程的信号队列中,而进程可以在任何时候通过执行信号处理函数来响应这些信号。

由于信号的异步特性,它们可以即时通知进程发生了某些事件,而无需进程进行轮询或等待。这使得信号成为一种快速且有效的进程间通信机制,尤其适用于需要快速响应的情况。

1.2 信号的目的

Linux系统信号的主要目的是提供一种快速、异步的进程间通信机制,用于通知进程发生了某些特定的事件或条件。信号有以下几个主要来源:

  • 硬件异常:硬件发生异常,即硬件检测到错误条件并通知内核,随即再由内核发送相应的信号给相关进程。如浮点错误(如除以零),会由硬件触发并由内核转换为信号(如SIGFPE)发送给进程。

  • 用户生成:用于在终端下输入了能够产生信号的特殊字符。用户可以通过键盘组合键(如Ctrl+C产生SIGINT)来生成断信号,通过这个方法可以终止在前台运行的进程;按下 CTRL + Z 组合按键可以产生暂停信号(SIGCONT),可以暂停当前前台运行的进程。

  • 进程间通信:进程调用 kill()系统调用可将任意信号发送给另一个进程或进程组。 当然对此是有所限制的,接收信号的进程和发送信号的进程的所有者必须相同,亦或者发送信号的进程的所有者是 root 超级用户。

  • 软件条件:软件条件,如进程使用abort函数,会生成SIGABRT信号,进程所设置的定时器已经超时、进程执行的 CPU 时间超限、进程的某个子进程退出等等情况。

  • 系统调用:某些系统调用在特定情况下会触发信号。例如,readwrite操作在对应文件描述符变为非阻塞状态且没有数据可读或写时,可能会触发EAGAIN错误,这可以被看作是一种信号。

  • 内核生成:操作系统内核在检测到某些条件时会生成信号。例如,当进程试图执行非法操作或访问无效内存时,内核会发送SIGILL或SIGSEGV。

  • 自定义信号:应用程序可以定义自己的信号处理逻辑,以响应自定义的信号,如SIGUSR1和SIGUSR2。

1.3 信号如何处理

信号通常是发送给对应的进程,当信号到达后, 该进程需要做出相应的处理措施,可以通过以下几种方式来处理信号:

  • 忽略信号:进程可以选择忽略某些信号,使其不产生任何效果。例如,使用signalsigaction函数将信号处理函数设置为SIG_IGN。事实上,大多数信号都可以使用这种方式进行处理,但有两种信号却决不能被忽略,它们是 SIGKILL 和 SIGSTOP,它们是Linux内核保留的信号,用于立即终止和暂停进程,这两个信号的设计是为了在紧急情况下强制终止或暂停进程,确保系统能够迅速响应严重错误或管理员的干预。

  • 捕获信号:进程可以定义信号处理函数(也称为信号捕获函数或信号处理程序),当信号被发送到进程时,该函数将被调用。

  • 默认操作:如果进程没有特别指定如何处理某个信号,那么信号将执行其默认操作。例如,SIGKILL和SIGSTOP信号的默认操作是终止进程,而SIGCHLD信号的默认操作是忽略。

  • 阻塞信号:进程可以暂时阻止某些信号的传递,直到进程再次允许这些信号。这可以通过sigprocmask函数实现。

2 信号的分类

2.1 可靠信号与不可靠信号

在Linux系统中,信号可以分为可靠信号和不可靠信号,这种分类主要是基于信号的传递和处理机制:

  • 不可靠信号(Unreliable Signals):这类信号可能在发送给进程时丢失,尤其是在高负载或大量信号同时发送的情况下。它们通常用于通知进程发生了某些事件,但不保证进程一定会接收到这些信号。

  • 可靠信号(Reliable Signals)可靠信号确保一旦发送,就会传递给进程,并且会被进程接收。这些信号通常用于控制进程的生命周期,如终止或暂停进程。

在 Linux 系统下使用"kill -l"命令可查看到所有信号,如下所示:

括号" ) "前面的数字对应该信号的编号,编号 1~31 所对应的是不可靠信号,编号 34~64 对应的是
可靠信号,从图中可知,可靠信号并没有一个具体对应的名字,而是使用了 SIGRTMIN+N 或 SIGRTMAXN 的方式来表示。

2.2 实时信号与非实时信号

实时信号与非实时信号其实是从时间关系上进行的分类,与可靠信号与不可靠信号是相互对应的, 非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。

  • 非实时信号:也称为标准信号或传统信号,它们是Linux系统中默认的信号类型。这些信号的编号从1到31,包括常见的信号如SIGKILLSIGTERMSIGINT等。非实时信号的优先级较低,它们可以被进程忽略或捕获,并由进程定义的处理函数来处理。

  • 实时信号:实时信号是POSIX.1b标准的一部分,提供了比非实时信号更高的优先级。这些信号的编号从32开始,由SIGRTMINSIGRTMAX定义,具体数量依赖于系统实现。实时信号不能被进程忽略,必须通过信号处理函数来处理,或者使用sigaction设置为忽略。它们通常用于需要快速响应的场景,如多媒体应用或实时控制系统。

常见信号与默认行为

3.1 信号本质上是 int 类型数字编号

信号在Linux系统中确实是以整型数字编号来标识的,每个信号都有一个唯一的数字,通常从1开始递增。例如,SIGINT信号编号为2,SIGTERM信号编号为15。这些整型编号是信号的标识符,用于在程序中引用和操作信号。

然而,除了整型编号,信号还具有对应的宏定义,这些宏定义通常以SIG为前缀,后面跟着信号名称的缩写。例如,SIGINT代表中断信号,SIGTERM代表终止信号。使用宏定义而不是直接使用整型编号可以使代码更易读和维护。

#define SIGHUP 1 /* Hangup (POSIX). */
#define SIGINT 2 /* Interrupt (ANSI). */
#define SIGQUIT 3 /* Quit (POSIX). */
#define SIGILL 4 /* Illegal instruction (ANSI). */
#define SIGTRAP 5 /* Trace trap (POSIX). */
#define SIGABRT 6 /* Abort (ANSI). */
#define SIGIOT 6 /* IOT trap (4.2 BSD). */
#define SIGBUS 7 /* BUS error (4.2 BSD). */
#define SIGFPE 8 /* Floating-point exception (ANSI). */
#define SIGKILL 9 /* Kill, unblockable (POSIX). */
#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */
#define SIGSEGV 11 /* Segmentation violation (ANSI). */
#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */
#define SIGPIPE 13 /* Broken pipe (POSIX). */
#define SIGALRM 14 /* Alarm clock (POSIX). */
#define SIGTERM 15 /* Termination (ANSI). */
#define SIGSTKFLT 16 /* Stack fault. */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGCHLD 17 /* Child status has changed (POSIX). */
#define SIGCONT 18 /* Continue (POSIX). */
#define SIGSTOP 19 /* Stop, unblockable (POSIX). */
#define SIGTSTP 20 /* Keyboard stop (POSIX). */
#define SIGTTIN 21 /* Background read from tty (POSIX). */
#define SIGTTOU 22 /* Background write to tty (POSIX). */
#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */
#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
#define SIGPOLL SIGIO /* Pollable event occurred (System V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */
#define SIGPWR 30 /* Power failure restart (System V). */
#define SIGSYS 31 /* Bad system call. */
#define SIGUNUSED 31

3.2 常见信号

前面说到, Linux 下对标准信号(不可靠信号、 非实时信号) 的编号为 1~31,如示例代码 8.1.1 所示,接下来将介绍这些信号以及这些信号所对应的系统默认操作。

编号信号名称描述系统默认操作
2SIGINT终端中断符,当用户在终端按下中断字符(通常是 CTRL + C)时,内核将发送 SIGINT 信号给前台进程组中的每一个进程。term
3SIGQUIT终端退出符,当用户在终端按下退出字符(通常是 CTRL + \)时,内核将发送 SIGQUIT 信号给前台进程组中的每一
个进程。
term+core
4SIGILL非法硬件指令,如果进程试图执行非法(即格式不正确)的机器语言指令,系统将向进程发送该信号。term+core
6SIGABRT异常终止(abort),如果进程试图执行非法(即格式不正确)的机器语言指令,系统将向进程发送该信号。term+core
7SIGBUS内存访问错误,产生该信号(总线错误, bus error)表示发生了某种内存访问错误。term+core
8SIGFPE算术异常,该信号因特定类型的算术错误而产生,譬如除以 0。term+core
9SIGKILL终极终止信号,SIGKILL此信号为“必杀(sure kill)”信号,用于杀死进程的终极办法,此信号无法被进程阻塞、忽略或者捕获,故而“一击必杀”,总能终止进程。term
10SIGUSR1用户自定义信号 1,该信号和 SIGUSR2 信号供程序员自定义使用,内核绝不会为进程产生这些信号,在我们的程序中,可以使用这些信号来互通通知事件的发生,或是进程彼此同步操作。term
11SIGSEGV无效的内存引用,这一信号非常常见,当应用程序对内存的引用无效时,操作系统就会向该应用程序发送该信号。term+core
12SIGUSR2用户自定义信号 2,与 SIGUSR1 信号相同。term
13SIGPIPE管道关闭,涉及到管道和 socket,当进程向已经关闭的管道、 FIFO 或套接字写入信息时,那么系统将发送该信号
给进程。
term
14SIGALRM定时器超时(alarm),应用程序中可以调用 alarm()或 setitimer()函数来设置一个定时器,当定时器定时时间到,那么内核将会发送 SIGALRM 信号给该应用程序term
15SIGTERM终止进程,SIGTERM通常用于请求进程正常终止。它是一种较为温和的终止信号,允许进程在终止前进行清理工作,比如保存状态、关闭文件描述符或释放资源。与SIGKILL(信号编号9)不同,用于立即强制终止进程。term
17SIGCHLD/SIGCLD子进程终止或停止,当父进程的某一个子进程终止时,内核会向父进程发送该信号。ignore
18SIGCONT使停止状态的进程继续运行,将该信号发送给已停止的进程,进程将会恢复运行。cont
19SIGSTOP停止进程,这是一个“必停”信号,用于停止进程(注意停止不是终止,停止只是暂停运行、进程并没有终止)。stop
20SIGTSTP终端停止符,也是一个停止信号,当用户在终端按下停止字符(通常是 CTRL + Z),那么系统会将 SIGTSTP 信号
发送给前台进程组中的每一个进程,使其停止运行。
stop
24SIGXCPU超过 CPU 限制,当进程的 CPU 时间超出对应的资源限制时,内核将发送此信号给该进程。term+core
26SIGVTALRM虚拟定时器超时,应用程序调用 setitimer()函数设置一个虚拟定时器,当定时器定时时间到时,内核将会发送该信号给进程。term
28SIGWINCH终端窗口尺寸发生变化,在窗口环境中,当终端窗口尺寸发生变化时(譬如用户手动调整了大小,应用程序调用 ioctl()设置了大小等),系统会向前台进程组中的每一个进程发送该信号。ignore
29SIGPOLL/SIGIO异步 I/O,用于提示一个异步 IO 事件的发生,譬如应用程序打开的文件描述符发生了 I/O 事件时,内核会向应用程序发送 SIGIO 信号。term/ignore
31SIGSYS无效系统调用,如果进程发起的系统调用有误,那么内核将发送该信号给对应的进程。term+core

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/39224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

艾体宝干货 | 解析Redis企业版的多租户技术

在多租户架构中,一个软件实例为多个不同的用户组(或“租户”)提供服务。每个租户的数据都被安全地隔离,确保它们对其他租户不可见且无法访问。可以将其想象为一栋公寓大楼,每个人都住在共享建筑中独立且隔离的单元中。…

大模型时代的基础架构,大模型算力中心建设指南重磅来袭!

什么是最畅销商品?什么是高毛利商品? 我们来看一个例子: 一件T恤使用成本为100元的原料,价格为140元。另一件T恤使用成本为80元的原料,但在样式、颜色、图案的设计上比较有特色,价格也为140元。 当这两件…

【JVM-04】线上CPU100%

【JVM-04】线上CPU100% 1. 如何排查2. 再举一个例子 1. 如何排查 ⼀般CPU100%疯狂GC,都是死循环的锅,那怎么排查呢?先进服务器,⽤top -c 命令找出当前进程的运⾏列表按⼀下 P 可以按照CPU使⽤率进⾏排序显示Java进程 PID 为 2609…

苏东坡传-读书笔记七

苏堤和西湖之与杭州,正如美女花容月貌上的双眸。我常想,倘若西湖之是空空的一片水——没有苏堤那秀美的修眉和虹彩般的仙岛,一画龙点睛增其神韵,那西湖该望之如何?几百年来的中国游客,春季到来之时,向西湖…

如何在Python中实现一个简单的爬虫程序

如何在Python中实现一个简单的爬虫程序 随着互联网的发展,数据已成为当今社会最宝贵的资源之一。而爬虫程序则成为了获取互联网数据的重要工具之一。本文将介绍如何在Python中实现一个简单的爬虫程序,并提供具体的代码示例。 确定目标网站 在开始编写爬…

【Python】已解决:urllib.error.HTTPError: HTTP Error 403: Forbidden

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决:urllib.error.HTTPError: HTTP Error 403: Forbidden 一、分析问题背景 在使用Python的urllib库中的urlopen或urlretrieve函数下载文件时,有时会遇到…

全国30省份各省资本存量数据固定资本形成总额永续盘存法(2000-2023年)

各省资本存量数据通过永续盘存法进行了详细的计算,这一方法覆盖了中国30个省份(不包括西藏),提供从2000年起直至2023的资本存量数据集。包括原始数据、测算过程、最终的资本存量结果。 以2000年作为基期年份,依据…

电路笔记(PCB):电流容量(IPC-2221和IPC-2152)+阻抗匹配

电流容量 IPC-2221经验公式 I K T b A c IK\times T^{b}\times A^{c} IKTbAc 这个公式用于估计PCB(Printed Circuit Board,印刷电路板)导线上的电流(I),其中T和A分别表示温度(Temperature&a…

flex布局中子元素内容超出时,子元素本身出现滚动条实现方法

flex布局中子元素宽度平均分配,并且当子元素内容超出时,子元素本身出现滚动条实现方法: 将父元素设置为display: flex,以启用Flexbox布局。将每个子元素的flex属性设置为1,以使其宽度平均分配。设置子元素的overflow属…

ComfyUI流程图、文生图、图生图步骤教学!

前言 leetcode , 209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的子数组 [numsl, numsl1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 …

大厂都在“抢滩”欧洲杯,你该如何蹭上热度?

2024欧洲杯战至第三轮小组赛,德国、瑞士、西班牙、意大利已出线角逐1/8决赛。 云略统计,欧洲杯开战至今,抖音上“欧洲杯”相关话题高达1000个,其中#谁是欧洲杯预言家 话题播放量高达7.57亿,C罗、姆巴佩等国际巨星更是频…

DB-100撕裂开关 JOSEF约瑟 合金接线端子,轻松接线

一、产品概述 型号:DB-100 主要用途:DB-100撕裂开关主要用于监测皮带输送机在运行过程中是否发生纵向撕裂,一旦发现撕裂情况,立即触发报警或停机,以保护设备和生产线的安全运行。 二、技术特点 检测原理:…

Snipaste截图工具的下载

Snipaste是一款简单而强大的桌面截图工具,它不仅支持快速截图,还提供了丰富的编辑和贴图功能,极大地提升了用户的工作效率。 网址:Snipaste 下载 1.进入文件夹解压缩 2.解压缩后打开双击运行 3.快捷键F1截图 F3截图固定桌面 …

2024年6月总结及随笔之打卡网红点

1. 回头看 日更坚持了547天。 读《人工智能时代与人类未来》更新完成读《AI未来进行式》开更并更新完成读《AI新生:破解人机共存密码》开更并持续更新 2023年至2024年6月底累计码字1267912字,累计日均码字2317字。 2024年6月码字90659字,…

泰勒展开式在Android系统或应用程序中的应用

泰勒展开式在Android系统或应用程序中的应用 引言 泰勒展开式(Taylor Series)是高等数学中的一个重要工具,它允许我们将一个复杂函数表示为一个无穷多项式的和,从而近似计算函数值。在Android开发中,理解和应用泰勒展开式有助于优化涉及复杂数值计算的算法,提高应用程序…

MySQL 9.0创新版发布!功能又进化了!

作者:IT邦德 中国DBA联盟(ACDU)成员,10余年DBA工作经验, Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主,全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯及Greenplum备份恢复, 安装迁移,性能优化、故障…

稳居C位的AIGC,真能让人人都成“设计大神”?

在当今数字化时代,随着人工智能技术的飞速发展,AIGC(AI Generated Content,即人工智能生成内容)已经逐渐成为设计领域的新宠。特别是在UI设计领域,AIGC的崛起引人注目,甚至有人宣称,…

大数据、人工智能、云计算、物联网、区块链序言【大数据导论】

各位大佬好 ,这里是阿川的博客,祝您变得更强 个人主页:在线OJ的阿川 大佬的支持和鼓励,将是我成长路上最大的动力 阿川水平有限,如有错误,欢迎大佬指正 本篇序言前 必看 【大数据导论】—大数据序言 这是…

以 Vue 3 项目为例,你是否经常遇到 import 语句顺序混乱的问题?要想解决它其实很容易!

大家好,我是CodeQi! 在项目开发过程中,我们经常会遇到项目中的 import 语句顺序混乱的问题。 这不仅会影响代码的可读性,还可能使我们代码在提交的时候产生不必要的冲突。 面对这种情况,要想解决它其实很容易。 通过合理的规范和自动化工具,我们可以确保 import 语句…

计算机网络 —— 路由协议:RIP、OSPF、BGP、MPLS

路由协议 1. 定义2. IGP2.1 RIP2.2 OSPF 3. BGP4. MPLS 1. 定义 互联网中需要通过路由将数据发送至目标主机。 路由器根据路由控制表(RoutingTable)转发数据包,它根据所收到的数据包中目标主机的IP地址与路由控制表的比较得出下一个应该接收的路由器。 &#xff…