【探索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++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

四氧化三钴和三元前驱体废水回收钴 钴回收树脂技术

钴是一种稀有金属&#xff0c;也是非常重要的过渡金属材料&#xff0c;因其优异的物理、化学性质&#xff0c;以化学品和金属的形式&#xff0c;广泛应用于锂电池、硬质合金、超耐热合金、绝缘材料和磁性材料、工业催化剂、染料及氧化钴的生产过程中。 钴可以提高锂离子电池的稳…

k8s-deployment控制器 5

K8s控制器是Kubernetes&#xff08;简称k8s&#xff09;系统中一个重要的组成部分&#xff0c;它是一个管理Pod的中间层&#xff0c;可以创建和管理多个Pod副本&#xff0c;确保它们按照预定的数量和行为进行运行。 通过编写yaml文件将信息全部存到etcd中&#xff0c;控制器通…

NX二次开发UF_CURVE_create_arc 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_create_arc Defined in: uf_curve.h int UF_CURVE_create_arc(UF_CURVE_arc_p_t arc_coords, tag_t * arc ) overview 概述 Creates an arc. You input the matrix tag, …

【超强笔记软件】Obsidian实现免费无限流量无套路云同步

【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步&#xff1f; 目录 一、简介 软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步 1 安装并设置Synology Drive套件 2 局域网内同步文件测试 三、内网穿透群…

PLC与组态王之间Modbus无线通讯的从站设置

本方案主要详述了在多台西门子300PLC与组态王之间Modbus无线通讯中如何设置从站。方案中所用到的无线通讯终端是DTD434MC——欧美系PLC专用无线通讯终端。 一、方案概述 无线Modbus网络组成如下&#xff1a; 二、测试背景 ● PC端组态软件版本&#xff1a;组态王6.55 ● 默…

错误:FinalShell连接CentOs连接失败

需要说明的是:这个错误不是首次连接发生的,而是多次使用后可能发生的错误 正文: 可能的原因是虚拟机的ip地址发生了变更,原因有以下几点: 最最可能的原因:1.DHCP分配变更&#xff1a; 如果虚拟机使用DHCP来获取IP地址&#xff0c;那么DHCP服务器可能会分配给虚拟机一个新的I…

Matplotlib散点图的创建_Python数据分析与可视化

Matplotlib散点图的创建 plot绘制散点图scatter画散点图plot与scatter效率对比 plot绘制散点图 散点图也是在数据科学中常用图之一&#xff0c;前面的文章我们学习了使用plt.plot/ax.plot画线形图的方法。同样的&#xff0c;现在用这些函数来画散点图&#xff1a; x np.lins…

掌握你的Mac,iStat Menus带你了解mac系统状态

iStat Menus for mac是一款强大的mac系统状态监控工具&#xff0c;它能够提供实时的系统信息和性能监测&#xff0c;帮助用户全面了解和管理自己的Mac设备。无论是CPU、内存、网络、硬盘还是传感器数据&#xff0c;iStat Menus都能直观地展示&#xff0c;并且支持自定义布局和样…

Linux - 动静态库(下篇)

前言 在上篇博客当中&#xff0c;对静态库是什么&#xff0c;怎么使用&#xff0c;简单实现自己的静态库&#xff0c;这些做了描述&#xff0c;具体请看上篇博客&#xff1a; 本篇博客将会对 动态库是什么&#xff0c;怎么使用&#xff0c;简单实现自己的动态库&#xff0c…

14 网关实战:网关聚合API文档

上节课介绍了网关层的认证鉴权,今天这节介绍一下网关层如何聚合API接口文文档。 为什么需要聚合API接口文档? 大型微服务系统模块众多,木谷博客系统就有9个,如果这些服务的接口地址没有一个统一,那么客户端将要保存每个服务的接口地址,这个肯定是不现实。 先来看一下A…

paddleocr笔记

PP-OCRv1 PP-OCR中&#xff0c;对于一张图像&#xff0c;需要完成以下3个步骤提取其中的文字信息&#xff1a; 使用文本检测方法&#xff0c;获取文本区域多边形信息&#xff08;PP-OCR中文本检测使用的是DBNet&#xff0c;因此获取的是四点信息&#xff09;。对上述文本多边形…

leetcode面试经典150题——33 最小覆盖子串(滑动窗口)

题目&#xff1a; 最小覆盖子串 描述&#xff1a; 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 “” 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字符串中…

67从零开始学Java之List集合有哪些特性?

作者&#xff1a;孙玉昌&#xff0c;昵称【一一哥】&#xff0c;另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、掘金优质作者、阿里云专家博主 前言 在上一篇文章中&#xff0c;壹哥给大家介绍了Java里的集合&#xff0c;我们了解了集合的由来、特点&a…

高防服务器和高防CDN的区别是什么?

现今大环境下攻击问题愈发严峻&#xff0c;许多网站有遇到被攻击导致网站崩溃&#xff0c;资源消耗的问题&#xff0c;那么这时候高防就是给为站长&#xff0c;企业等的第一选择了&#xff0c;那边目前高防CDN和高防服务器这两种抵御DDoS攻击的两种主流防御&#xff0c;那种会更…

在线陪诊系统: 医学科技的革新之路

医疗服务的数字化时代已经到来&#xff0c;而在线陪诊系统正是医学科技革新的杰出代表。通过巧妙的技术代码&#xff0c;这一系统不仅实现了患者和医生之间的远程互动&#xff0c;还将医疗服务推向了一个更加智能化的未来。在这篇文章中&#xff0c;我们将深入探讨在线陪诊系统…

大学招聘平台存在逻辑漏洞

找到一个学校的就业信息网&#xff0c; 随便点击一个招聘会&#xff0c;并且抓包查看返回包 注意返回包中的dwmc参数&#xff0c;这个是公司名称&#xff0c;zplxr参数这个是招聘人员姓名&#xff0c;lxdh参数是电话号码&#xff0c;这几个参数后面有用 在第一张图点击单位登…

正则表达式回溯陷阱

一、匹配场景 判断一个句子是不是正规英文句子 text "I am a student" 一个正常的英文句子如上&#xff0c;英文单词 空格隔开 英文单词 多个英文字符 [a-zA-Z] 空格用 \s 表示 那么一个句子就是单词 空格&#xff08;一个或者多个&#xff0c;最后那个单词…

MIT_线性代数笔记:第 08 讲 求解 Ax=b:可解性与结构

目录 可解的条件 Solvability conditions on b特解 A particular solution通解 Complete solution与零空间进行线性组合 Combined with nullspace 秩 Rank 可解的条件 Solvability conditions on b 矩阵 A 的第三行为第一行和第二行的加和&#xff0c;因此 Axb 中 b 的第 3 个分…

【vue ui 一直卡在 Starting GUI..】

vue ui 解决问题 1.如果项目一直卡在 Starting GUI..2.解决方法 (切换数据源)3.成功解决 1.如果项目一直卡在 Starting GUI… 2.解决方法 (切换数据源) 直接在cmd中输入如下 npm config set registry http://registry.npm.taobao.org/3.成功解决

C语言:求二维数组鞍点 。鞍点就是指二维数组中在该位置上的元素在该行上最大,在该列上最小,也可能没有鞍点。

分析&#xff1a; 在主函数 main 中&#xff0c;程序首先定义一个二维数组 a[5][5] 和五个整型变量 i、j、max、maxj 和 k&#xff0c;并用于寻找鞍点。然后使用 printf 函数输出提示信息。 接下来&#xff0c;程序使用两个 for 循环结构&#xff0c;从键盘输入一个 5x5 的二…