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

news2024/9/29 7:31:32

在这里插入图片描述

阅读导航

  • 引言
  • 一、阻塞信号
    • 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.coloradmin.cn/o/1262115.html

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

相关文章

振弦式轴力计和振弦采集仪组成的安全监测解决方案

振弦式轴力计和振弦采集仪组成的安全监测解决方案 振弦式轴力计和振弦采集仪是一种常用的结构安全监测工具&#xff0c;可以用于评估建筑物、桥梁、隧道或其他结构的结构健康状态和安全性能。这种监测方案较为先进、精确&#xff0c;并且能够监测长期的结构反应&#xff0c;因此…

环境土壤物理Hydrus2D/3D模型实践技术应用

HYDRUS是基于Windows系统界面开发的环境土壤物理模拟软件&#xff0c;是用于模拟一维和多维变饱和多孔介质的水分运动、溶质&#xff08;污染物等&#xff09;运移、根系吸水和溶质吸收、以及热量传导等方面的强有力工具。HYDRUS还包括一个参数优化算法&#xff0c;用于各种土壤…

elFinder ZIP 参数注入导致命令注入 (CVE-2021-32682)

漏洞描述 elFinder 是一个用于 Web 的开源文件管理器&#xff0c;使用 jQuery UI 用 JavaScript 编写。 在 elFinder 2.1.48 及更早版本中发现一个参数注入漏洞。此漏洞可能允许攻击者在托管 elFinder PHP 连接器的服务器上执行任意命令&#xff0c;即使配置最少也是如此。这…

MySQL用得好好的,为何要转ES?

MySQL是一种关系型数据库&#xff0c;它可以高效地存储和查询结构化的数据。 ES是一种分布式搜索引擎&#xff0c;它可以快速地对海量的非结构化或半结构化的数据进行全文检索和分析。 MySQL 和 ES 的数据存储方式也不同。MySQL 中的数据通常是以关系型表的形式存储在磁盘上&…

第二十章(多线程)

一.线程的简介 Windows操作系统是多任务操作系统&#xff0c;它以进程为单位。一个进程是一个包含有自身地址的程序&#xff0c;每个独立执行的程序都称为进程。也就是说每个正在执行的程序都是一个进程。系统可以分配给每一个进程有一段有限的使用CPU的时间&#xff08;也可以…

Echarts tooltip配置项的属性 图表悬浮框

这个小图标就是tooltip的配置项 tooltip:{} //默认样式 自定义显示数据 如果没有自定义的属性可以 只是写data [1254,1551,574,10]… series: {//图表配置项 如大小&#xff0c;图表类型name: 图表名字,type: bar,//图表类型data: [{value: 454,time: 2012-11-12},{value: 898…

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(6)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

Python用itertools.product函数生成10位的0,1组合

需求&#xff1a;有10个指标&#xff0c;每个指标有0、1两种结果&#xff0c;生成所有可能出现的情况。解决&#xff1a;基于数学知识&#xff0c;我们很容易知道总共有组合数为2^101024种 那么使用python我们该如何用代码实现呢&#xff1f; python中的函数为itertools.produ…

ArkUI 如何将$r(’app.string.xxx‘) 转成string字符串

一、正常引用字符串资源文件内容 在 ArkUI 中&#xff0c;string.json 中的字符串资源正常情况下使用如下方式引用&#xff1a; Entry Component struct LoginPage {build() {Column() {Text($r(app.string.title))}}}二、资源转string类型 上面的代码没问题是因为 Text(con…

283. 移动零(双指针)

一次遍历&#xff0c;j相当于遍历到第一个零元素&#xff0c;将其和非零元素i交换&#xff0c; 使用的是leetcode题解的动图 class Solution { public:void moveZeroes(vector<int>& nums) {int n nums.size();int j 0;for (int i 0; i < n; i) {if (nums[i]…

Java多线程核心技术二-synchronzied同步方法

1 概述 关键字synchronzied保障了原子性、可见性和有序性。 非线程安全问题会在多个线程对同一个对象中的同一个实例变量进行并发访问时发生&#xff0c;产生的后果就是“脏读”&#xff0c;也就是读取到的数据其实是被更改过的。而线程安全是指获取的实例变量的值是经过同步处…

坚鹏:中国人寿福建省公司当下宏观经济形势分析与二十大精神解读

中国人寿保险&#xff08;集团&#xff09;公司属国家大型金融保险企业&#xff0c;2016年中国人寿入主广发银行&#xff0c;开启保险、投资、银行三大板块协同发展新格局。2022年&#xff0c;集团公司合并营业收入站稳万亿平台&#xff1b;合并总资产突破6万亿元大关。中国人寿…

java学习part18抽象类

Java抽象类 详解-CSDN博客 111-面向对象(高级)-抽象类与抽象方法的使用_哔哩哔哩_bilibili 1.概念 2.抽象类 抽象类不能实例化&#xff0c;可以有属性&#xff0c;也可以有方法。 方法可以实现或者只声明不实现&#xff0c;要加一个abstract abstract class A{//定义一个抽…

操作系统 选择题 期末试题 考研真题 + 参考答案

1.&#xff08;考研真题&#xff0c;单项选择题&#xff09;单道批处理系统的主要缺点是&#xff08; &#xff09;。 A. CPU利用率不高 B.失去了交互性 C.不具备并行性 D.以上都不是 【参考答案】A 【解析】单道批处理系统的内存中只有一道程序&#xff0c;当该程序…

智能优化算法应用:基于郊狼算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于郊狼算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于郊狼算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.郊狼算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

C 语言-循环嵌套-函数

C 语言 - 循环嵌套、函数 1. 循环嵌套 1.1 作用 循环 套 循环。 1.2 使用 需求1&#xff1a; 打印以下图形&#xff1a; * * * * * * * * * * * * * * * *代码&#xff1a; 1、使用循环打印 #include <stdio.h> int main(int argc, char const *argv[]) {for (int i…

zabbix 6.0 原理与部署

一、zabbix简介&#xff1a; zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 zabbix 能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 zabbi…

Mysql中的引擎介绍(InnoDB,MyISAM,Memory)

MySQL引擎就是指表的类型以及表在计算机上的存储方式。 MySQL数据库及其分支版本主要的存储引擎有三种&#xff0c;分别是 InnoDB、MyISAM、 Memory&#xff0c;还有一些其他的&#xff0c;CSV、Blackhole等&#xff0c;比较少见&#xff0c;可以使用SHOW ENGINES语句来查看。结…

计算机组成原理——小啃一下

CPU和主存储器结构 CPU&#xff1a; 运算器 ACC&#xff08;累加器&#xff09;ALU&#xff08;算数逻辑单元&#xff09;MQ&#xff08;乘商寄存器&#xff09;X&#xff08;操作数寄存器&#xff09; 控制器 CU&#xff08;控制单元&#xff09;IR&#xff08;指令寄存器&a…

基础课12——深度学习

深度学习技术是机器学习领域中的一个新的研究方向&#xff0c;它被引入机器学习使其更接近于最初的目标——人工智能。深度学习的最终目标是让机器能够像人一样具有分析学习能力&#xff0c;能够识别文字、图像和声音等数据。 深度学习的核心思想是通过学习样本数据的内在规律…