【探索Linux】—— 强大的命令行工具 P.17(进程信号 —— 信号保存 | 阻塞信号 | sigprocmask() | sigpending() )

在这里插入图片描述

阅读导航

  • 引言
  • 一、阻塞信号
    • 1. 信号相关常见概念
      • (1)信号递达
      • (2)信号未决
      • (3)阻塞信号
      • (4)忽略信号
    • 2. 信号在内核中的表示
      • ⭕信号在内核中的表示示意图
    • 3. sigset_t (数据类型)
    • 4. 信号集操作函数
  • 二、sigprocmask() 函数
  • 三、sigpending() 函数
  • 温馨提示

引言

在计算机科学领域,信号是一种重要的通信机制,用于处理各种系统事件和进程间的通信。Linux作为一个开源操作系统,以其稳定性和高度可定制性而闻名。在Linux下,信号的处理是实现进程间通信和事件处理的关键机制之一。

本文将继续探讨Linux下信号的相关主题,着重介绍信号的保存、阻塞以及sigprocmask函数的用法。通过深入了解这些概念和技术,我们能够更好地掌握Linux信号处理的原理和方法,提高系统的可靠性和稳定性。

通过本文的学习,读者将对Linux下信号的保存、阻塞和sigprocmask函数有更深入的了解。这些知识将帮助读者在开发和维护Linux应用程序时更好地处理信号,提高系统的稳定性和性能。无论是初学者还是有经验的开发人员,都将受益于本文所涵盖的内容。让我们一起深入研究Linux信号处理的精髓吧!

一、阻塞信号

1. 信号相关常见概念

(1)信号递达

信号递达是指当信号被发送和接收后,信号的处理过程。在Linux中,进程可以通过系统调用kill()向其他进程发送信号,同时也可以接收来自其他进程的信号。当信号被发送到一个进程时,需要经过多个步骤才能被接收并处理:

  1. 发送信号:进程A使用kill()系统调用向进程B发送信号。

  2. 信号递送:信号从进程A发送到进程B,进程B接收到信号。

  3. 信号处理:进程B根据信号的类型和处理方式来进行相应的处理。

在Linux中,每个信号都有一个默认的处理方式。例如,SIGKILL信号会强制终止进程,而SIGINT信号会让进程中断并退出。然而,进程也可以通过signal()系统调用或sigaction()系统调用来改变信号的处理方式,以便实现更灵活的信号处理行为。

🚨注意在信号递送和信号处理的过程中,可能会发生信号丢失或者信号被阻塞的情况。当一个进程处于阻塞状态时,它将无法接收到任何信号,直到解除了阻塞状态。如果多个信号同时到达进程时,可能会出现信号排队的情况,此时进程需要按照一定的规则来处理这些信号。

(2)信号未决

在Linux中,信号未决(Pending Signal)指的是一个进程接收到但尚未处理的信号。当一个信号被发送给一个进程时,如果该进程当前正在执行某个信号处理函数或者该信号已经处于未决状态,则该信号会被放入进程的信号未决位集(Pending Signal Mask)中,等待进程从信号处理函数返回后进行处理。

在信号未决位集中,每个位代表一个信号,如果该位为1,则表示该位对应的信号处于未决状态。一个进程可以通过sigpending()系统调用来查询自己的信号未决位集

如果一个进程接收到多个同类型的信号并且信号处理函数尚未返回,则这些信号将被合并成一个信号,并只记录一次信号未决。进程可以使用sigprocmask()系统调用来设置或修改信号未决掩码,以控制哪些信号可以被接收和处理。

🚨注意:当进程解除信号阻塞状态后,它必须处理所有未决的信号,否则这些信号将继续被保留在信号未决位集中,可能会导致信号丢失或者其他问题。因此,在处理信号的过程中,要注意及时处理所有未决信号,避免信号积压导致系统异常。

(3)阻塞信号

阻塞信号是指进程可以选择暂时延迟处理某些特定信号的传递和处理。在Linux中,进程可以通过设置信号阻塞掩码(Signal Mask)来达到这一目的。

当一个信号被发送给一个进程时,内核会首先检查该信号是否在进程的信号阻塞掩码中。如果信号在阻塞掩码中,则该信号将被暂时挂起,直到该信号从阻塞状态解除后才能被处理。进程可以使用sigprocmask()系统调用来修改信号阻塞掩码。

通过设置信号阻塞掩码,进程可以灵活地控制哪些信号可以被接收和处理,以及在何种情况下可以延迟处理某些信号。这种机制在多线程编程和信号处理复杂的应用中尤为重要。

🚨注意当进程解除对某个信号的阻塞时,如果有多个该类型的信号在阻塞期间到达,那么这些信号将按照某种规则进行排队,等待进程逐个处理。另外,即使信号被阻塞,但仍然会记录在信号未决位集中,等待进程解除阻塞后处理。

(4)忽略信号

忽略信号是指进程可以选择不对某些特定信号进行处理,即忽略该信号的传递和默认处理行为。在Linux中,进程可以通过设置信号处理函数为SIG_IGN来达到这一目的。

当一个信号被发送给一个进程时,内核会首先检查该信号的处理方式。如果进程将该信号的处理函数设置为SIG_IGN(忽略信号),则内核将不对该信号进行任何处理,直接丢弃该信号。

通过忽略信号,进程可以屏蔽一些不需要处理的信号,从而避免其产生默认的处理行为。对于某些特定的信号,可能会存在一些默认的处理行为,比如终止进程、终止进程并生成core文件等。通过忽略信号,进程可以防止这些默认的处理行为发生。

🚨注意并非所有的信号都可以被忽略。一些重要的信号,如SIGKILL和SIGSTOP,默认情况下是不能被忽略的,它们具有固定的处理行为。此外,一些特殊的信号,如SIGCHLD,可以被设置为忽略,但是会导致一些系统资源无法正确释放,因此需要谨慎使用。

2. 信号在内核中的表示

⭕信号在内核中的表示示意图

在这里插入图片描述

  • 每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
  • SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
  • SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信号。

3. sigset_t (数据类型)

sigset_t 是一个数据类型,用于表示信号集。它是一个由位图组成的数据结构,用于跟踪和管理多个信号的状态。在 C 语言中,sigset_t 常常以无符号整数或者数组的形式实现

在 Linux 中,sigset_t 是通过使用位操作来表示信号集的。每个信号对应 sigset_t 中的一个位(bit),如果某个位被设置为 1,则表示相应的信号在该信号集中被包含;如果某个位被设置为 0,则表示相应的信号在该信号集中不被包含。

sigset_t 通常用于以下操作:

  • 设置信号集中的某个位:可以使用宏函数 sigaddset()sigemptyset() 来设置信号集中的位。sigaddset() 可以将指定的信号添加到信号集中,而 sigemptyset() 可以清空信号集。
  • 清除信号集中的某个位:可以使用宏函数 sigdelset() 来清除信号集中的位,从而从信号集中删除指定的信号。
  • 检查信号集中的某个位是否被设置:可以使用宏函数 sigismember() 来检查信号集中的位是否被设置,从而判断指定的信号是否在信号集中。

sigset_t 的使用可以帮助进程或线程控制和管理信号的行为,如阻塞或解除阻塞某些信号,判断信号是否被阻塞等。在信号处理函数中,可以通过调用相关的系统调用来获取和修改当前进程或线程的 sigset_t,以实现对信号的处理和控制。

4. 信号集操作函数

在C语言中,可以使用以下函数来进行信号集(sigset_t)的操作:

函数功能
sigemptyset(sigset_t *set)清空信号集,将所有信号从集合中移除。
sigfillset(sigset_t *set)将所有信号添加到信号集中,使其包含所有信号。
sigaddset(sigset_t *set, int signum)将指定的信号添加到信号集中。
sigdelset(sigset_t *set, int signum)从信号集中删除指定的信号。
sigismember(const sigset_t *set, int signum)检查指定的信号是否在信号集中,如果在返回1,否则返回0。

这些函数都返回一个整数值来表示操作的成功与否。如果函数执行成功,返回值为0;如果函数执行失败,返回值为-1,并设置相应的错误号(errno)。

这些函数通常用于与信号处理相关的操作,例如设置阻塞信号集、检查信号是否被阻塞、解除阻塞等。通过操作信号集,可以对进程接收和处理的信号进行控制。

需要包含 <signal.h> 头文件才能使用上述函数。此外,还有其他一些与信号处理相关的函数,如 sigprocmask()sigpending() 等,它们也可用于信号集的操作和管理。

二、sigprocmask() 函数

sigprocmask() 函数用于更改或检索进程的信号屏蔽字(signal mask)。信号屏蔽字决定了进程当前阻塞的信号集,即哪些信号在被阻塞的情况下不能被进程接收到。

#include <signal.h>int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

sigprocmask() 函数接受三个参数:

  • how:用于指定对信号屏蔽字的操作。
操作类型描述
SIG_BLOCKset 指向的信号集中的信号添加到当前的信号屏蔽字中。
SIG_UNBLOCK从当前的信号屏蔽字中移除 set 指向的信号集中的信号。
SIG_SETMASK将当前的信号屏蔽字替换为 set 指向的信号集。
  • set:一个指向 sigset_t 类型的指针,指向要设置的新的信号屏蔽字。
  • oldset:可选参数,如果不为 NULL,则旧的信号屏蔽字将被存储在 oldset 指向的位置。

sigprocmask() 函数返回值表示操作的成功与否。如果函数执行成功,返回值为0;如果函数执行失败,返回值为-1,并设置相应的错误号(errno)。

以下示例演示了如何使用 sigprocmask() 函数:

#include <stdio.h>
#include <signal.h>int main() {sigset_t newset, oldset;// 设置要阻塞的信号集sigemptyset(&newset);sigaddset(&newset, SIGINT);// 阻塞 SIGINT 信号if (sigprocmask(SIG_BLOCK, &newset, &oldset) == -1) {perror("sigprocmask");return 1;}printf("SIGINT is blocked. Press Ctrl+C to send the signal.\n");// 挂起进程,等待信号到达pause();// 恢复原来的信号屏蔽字if (sigprocmask(SIG_SETMASK, &oldset, NULL) == -1) {perror("sigprocmask");return 1;}printf("SIGINT is unblocked. Signal handling resumed.\n");return 0;
}

上述示例将 SIGINT 信号添加到新的信号屏蔽字中,然后使用 sigprocmask() 函数将其阻塞。当程序运行时,按下 Ctrl+C 将发送 SIGINT 信号,但由于该信号被阻塞,进程挂起直到信号解除阻塞后才继续执行。在恢复原来的信号屏蔽字后,程序可以正常处理 SIGINT 信号。

在这里插入图片描述

三、sigpending() 函数

sigpending() 函数用于获取当前进程挂起(pending)的信号集,即已经产生但尚未被进程处理的信号

#include <signal.h>int sigpending(sigset_t *set);

sigpending() 函数接受一个指向 sigset_t 类型的指针作为参数,用于存储当前挂起的信号集。该函数将会将当前进程挂起的信号填充到 set 指向的信号集中。

sigpending() 函数返回值表示操作的成功与否。如果函数执行成功,返回值为0;如果函数执行失败,返回值为-1,并设置相应的错误号(errno)。

以下示例演示了如何使用 sigpending() 函数:

#include <stdio.h>
#include <signal.h>void handler(int signum) {printf("Received signal: %d\n", signum);
}int main() {sigset_t pending_set;// 设置信号处理函数signal(SIGINT, handler);// 发送 SIGINT 信号raise(SIGINT);// 获取挂起的信号集if (sigpending(&pending_set) == -1) {perror("sigpending");return 1;}// 检查 SIGINT 是否在挂起的信号集中if (sigismember(&pending_set, SIGINT)) {printf("SIGINT is pending.\n");} else {printf("SIGINT is not pending.\n");}return 0;
}

上述示例中,首先定义了一个信号处理函数 handler,当接收到 SIGINT 信号时,该函数将被调用。然后使用 signal() 函数将 SIGINT 信号与该处理函数关联。

接下来,通过调用 raise(SIGINT) 发送 SIGINT 信号给当前进程。

然后,使用 sigpending() 函数获取当前挂起的信号集,并将结果存储在 pending_set 中。

最后,使用 sigismember() 函数检查 SIGINT 是否在挂起的信号集中,根据结果输出相应的信息。

请注意,由于信号的处理是异步的,在获取挂起的信号集之前,可能已经有其他信号被处理掉了。因此,sigpending() 只能提供当前未被处理的挂起信号的部分信息。

温馨提示

感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述

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

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

相关文章

viple模拟器使用(三):unity模拟器中实现沿右墙迷宫算法

沿右墙迷宫算法原理 默认直行&#xff1b;右侧有路&#xff0c;则右转&#xff1b;前方无路&#xff0c;则左转。 由于unity模拟器中使用机器人移动动力控制和机器人转动角度控制来实现控制机器人前进、后退、暂停、左转、右转 。 程序编写 主机以及配置 通过内建事件初始化机…

云表|低代码助力职场人,一招制敌解决办公难题

身在职场&#xff0c;我们时常会面临一系列令人头疼的难题&#xff1a; ● 突然被领导要求30分钟内汇总所有人的填报信息&#xff0c;看着面前格式五花八门的Excel表格&#xff0c;我们无所适从&#xff0c;不知从何下手。 ● 在这个数字化的时代&#xff0c;公司仍然沿用古老的…

【数据中台】开源项目(2)-Davinci可视应用平台

1 平台介绍 Davinci 是一个 DVaaS&#xff08;Data Visualization as a Service&#xff09;平台解决方案&#xff0c;面向业务人员/数据工程师/数据分析师/数据科学家&#xff0c;致力于提供一站式数据可视化解决方案。既可作为公有云/私有云独立部署使用&#xff0c;也可作为…

【操作宝典】SQL巨擘:掌握SQL Server Management的终极秘籍!

目录 ⛳️【SQL Server Management】 ⛳️1. 启动登录 ⛳️2. 忘记密码 ⛳️3. 操作数据库和表 3.1 新建数据库text 3.2 新建表 3.3 编辑表 3.4 编写脚本 ⛳️【SQL Server Management】 ⛳️1. 启动登录 需要开启服务 ⛳️2. 忘记密码 登录windows--> 安全性 -->…

pikachu靶场:php反序列化漏洞

pikachu靶场:php反序列化漏洞 文章目录 pikachu靶场:php反序列化漏洞代码审计漏洞利用 代码审计 像这种反序列化的代码基本都是代码审计出的 // 定义一个名为S的类&#xff0c;该类有一个属性$test和一个构造函数 class S{ var $test "pikachu"; // $test是一个…

【1】AR Tag 在ros中的使用

1.定义 AR Tag 是一种用于增强现实&#xff08;AR&#xff09;应用中的视觉标记&#xff0c;用于跟踪和定位虚拟物体在现实世界中的位置。 AR Tag由黑白正方形图像表示&#xff0c;图像内部有黑色边框中的某些图案。它与我们经常用到的二维码长得类似&#xff0c;原理其实也一…

elementui的table合并列,三个一组

<el-table :span-method"objectSpanMethod" :cell-style"iCellStyle" :data"tableData" height"63vh" border style"width: 100%; margin-top: 6px"><el-table-column type"index" label"序号"…

5V摄像机镜头驱动IC GC6208,可用于摄像机,机器人等产品中可替代AN41908

GC6208是一个镜头电机驱动IC摄像机和安全摄像机。该设备集成了一个直流电机驱动器的Iris的PID控制系统&#xff0c;也有两个通道的STM电机驱动器的变焦和对焦控制。 芯片的特点: 内置用于Iris控制器的直流电机驱动器 内置2个STM驱动程序&#xff0c;用于缩放和…

Python内置函数与标准库函数的解释示例

一、内置函数与标准库函数的区分 Python 解释器自带的函数叫做内置函数&#xff0c;这些函数可以直接使用&#xff0c;不需要导入某个模块。 Python 解释器也是一个程序&#xff0c;它给用户提供了一些常用功能&#xff0c;并给它们起了独一无二的名字&#xff0c;这些常用功能…

汽车电子 -- 车载ADAS之RCTA(后方横向来车预警 )

国际标准: RCTA: GB/T XXXXX—XXXX 乘用车后部交通穿行提示系统性能要求及试验方法 一、后方横向来车预警RCTA&#xff08; Rear Cross Traffic Assist&#xff09; 在车辆倒车时&#xff0c;实时监测车辆后方横向接近的其它道路使用者&#xff0c;并在可能发生碰撞危险时发…

第20章多线程

创建线程 继承Thread 类 Thread 类时 java.lang 包中的一个类&#xff0c;从类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行&#xff0c;任务是指线程在启动时执行的工作&#xff0c;start() 方法启动线程&am…

什么是yum?

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f…

C#开发的OpenRA游戏之属性SelectionDecorations(12)

C#开发的OpenRA游戏之属性SelectionDecorations(12) 前面分析了显示选择框的指示器类SelectionBoxAnnotationRenderable,它的作用就是画一个四个角的方角。 这个类是在属性SelectionDecorations里调用的,如下: protected override IEnumerable<IRenderable> Rende…

JOSEF 综合继电器 HJZZ-32/2 AC220V 合闸延时整定0.02-9.99S

系列型号&#xff1a; HJZZ-91分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/1分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/2分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/2A分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/3分闸、合闸、电源监视综…

【机器学习】决策树

一、原理 典型的决策树 分类树与回归树 如何用训练样本建立决策树 分裂规则 不纯度 各种不纯度指标定义 对于数值型特征和分类型特征分别详述确定分裂阈值和分裂特征的过程 对于分类树和回归树如何确定叶子节点的值 对于样本特征向量属性缺失情况如何处理 对于属性缺失情况&am…

android自定义桌面应用

android自定义桌面应用 这篇文章主要讲下自定义桌面应用. 效果主要是调用packageManager来获取当前所有的程序,并在自定义桌面程序中展示,并支持跳转. 主要的代码如下: 1.manifest声明 <activity android:name".MainActivity"><intent-filter><ac…

【uniapp】微信运行报错TypeError_ Cannot read property ‘FormData‘ of undefined

文章目录 一、报错详情&#xff1a;二、解决&#xff1a; 一、报错详情&#xff1a; 二、解决&#xff1a; npm install axios0.27.2 #或者 npm install axios1.3.4

<JavaEE> Java中线程有多少种状态(State)?状态之间的关系有什么关系?

目录 一、系统内核中的线程状态 二、Java中的线程状态 一、系统内核中的线程状态 状态说明就绪状态线程已经准备就绪&#xff0c;随时可以接受CPU的调度。阻塞状态线程处于阻塞等待&#xff0c;暂时无法在CPU中执行。 二、Java中的线程状态 相比于系统内核&#xff0c;Java…

内测分发平台是否支持应用的微服务化部署

内测分发平台的微服务化部署支持是现代应用开发和部署的一个重要特性。首先我们得知道什么是微服务化部署都有哪些关键功能&#xff0c;如何实施微服务化的部署。下文以我自己理解总结了几点。 图片来源:news.gulufenfa.com 微服务是一种基于独立运行的小型服务来构建应用程序…

ILSVRC2012数据集处理

ILSVRC2012数据集处理 解压图像处理标签和图像 解压图像 先解压 tar -xvf ILSVRC2012_img_train.tar 解压之后其实还是1000个tar压缩包&#xff08;对应1000个类别&#xff09;&#xff0c;需要再次解压&#xff0c;解压脚本unzip.sh如下&#xff08;PS&#xff1a;可能需要自…