【Linux】信号-下

news2025/1/10 17:47:16

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
🌎推荐文章:【LeetCode】winter vacation training

在这里插入图片描述


目录

  • 👉🏻信号递达,信号未决,信号阻塞
    • block表 ,pending表 ,handler表
    • sigset_t类型
  • 👉🏻信号集操作函数
    • 常见信号集操作函数
    • sigaction函数
    • sigprocmask函数
    • sigpending函数

👉🏻信号递达,信号未决,信号阻塞

在操作系统中,进程之间可以通过信号进行通信。当一个进程向另一个进程发送信号时,会出现以下几种情况:信号递达、信号未决和信号阻塞。

  1. 信号递达(Signal Delivery):当一个进程向目标进程发送信号时,操作系统会将该信号递送给目标进程。递达的信号会触发目标进程相应的信号处理函数(signal handler)执行,或者引起默认的信号处理行为。这意味着信号已经成功传递到了目标进程。

  2. 信号未决(Signal Pending):如果目标进程正在处理一个信号,而此时又有一个相同的信号递达给它,那么这个信号就会被标记为未决状态。未决信号是一种被记录下来但尚未被处理的信号

  3. 信号阻塞(Signal Blocking):进程可以选择性地阻塞某些信号,使得它们在阻塞状态下不会递达到该进程。当信号被阻塞时,即使有该信号的递达请求,进程也不会接收到该信号。当解除对信号的阻塞时,之前被阻塞的信号会立即递达到进程。

信号被阻塞——>信号一定是未决状态

block表 ,pending表 ,handler表

在内核中,信号是一种异步事件,可能随时被发送给进程,并且进程需要及时响应。为了管理信号的处理过程,内核维护了三个重要的数据结构:block表、pending表和handler表。
在这里插入图片描述

  1. block表:用于记录被阻塞的信号集合。当一个进程调用sigprocmask函数时,它可以指定一组要阻塞的信号。这些信号会被放入该进程对应的block表中,使得它们在阻塞状态下不会递达到该进程。当进程需要解除对某个信号的阻塞时,可以再次调用sigprocmask函数来修改block表。

  2. pending表:用于记录未决的信号集合。当一个信号递达到目标进程时,如果目标进程正在处理另外一个相同的信号,那么这个信号就会被标记为未决状态,放入该进程对应的pending表中。当当前信号处理完毕后,内核会检查pending表中是否有未决的信号,如果有,则将它们取出并递达到进程。

  3. handler表:用于记录每种信号对应的信号处理函数。当一个信号递达到目标进程时,内核会根据该信号对应的handler表中的处理函数来执行相应的操作。如果进程没有安装该信号的处理函数,则会执行默认的信号处理行为。

这些表都是在进程控制块(PCB)中维护的,并且可以通过一些系统调用和库函数来修改和查询。例如,sigprocmask函数可以修改block表,sigpending函数可以查询pending表,signal和sigaction函数可以修改handler表。

sigset_t类型

sigset_t 是一个数据类型,用于表示一组信号的集合。在 POSIX 标准中,sigset_t 被定义为一个整数数组。

使用 sigset_t 可以方便地管理进程的信号屏蔽字和未决信号集合。进程的信号屏蔽字是一个 sigset_t 类型的变量,它用于标记哪些信号是被阻塞的。当一个信号被阻塞时,即使该信号有递达请求,也不会发送给进程。我们可以使用 sigprocmask 系统调用来修改进程的信号屏蔽字(信号屏蔽集合)。

另外,sigset_t 还可以用于查询进程的未决信号集合。未决信号集合记录了已经递达到进程,但尚未被处理的信号。我们可以使用 sigpending 系统调用来查询未决信号集合。该函数会将未决信号集合写入 sigset_t 类型的变量中返回。

在使用 sigset_t 时,我们可以使用一些辅助函数来对信号集合进行操作。例如:

  • sigemptyset:将一个信号集合清空,即将该集合中所有信号都设置为未包含状态。
  • sigfillset:将一个信号集合填充满,即将该集合中所有信号都设置为包含状态。
  • sigaddset:将一个信号添加到信号集合中。
  • sigdelset:将一个信号从信号集合中删除。

这些辅助函数可以方便我们对信号集合进行操作,从而更好地管理进程的信号处理。

👉🏻信号集操作函数

常见信号集操作函数

当使用 sigset_t 表示信号集合时,可以使用以下函数进行信号集合的操作:

  1. int sigemptyset(sigset_t *set)
    该函数用于清空信号集合,将所有信号都设置为未包含状态(比特位清0)。它会将 set 指向的信号集合清空,成功返回0,失败返回-1。

  2. int sigfillset(sigset_t *set)
    该函数用于填充信号集合,将所有信号都设置为包含状态(比特位置为1)。它会将 set 指向的信号集合填充满,成功返回0,失败返回-1。

  3. int sigaddset(sigset_t *set, int signum)
    该函数用于将指定的信号添加到信号集合中。set 是要操作的信号集合的指针,signum 是要添加的信号编号。成功返回0,失败返回-1。

  4. int sigdelset(sigset_t *set, int signum)
    该函数用于从信号集合中删除指定的信号。set 是要操作的信号集合的指针,signum 是要删除的信号编号。成功返回0,失败返回-1。

  5. int sigismember(const sigset_t *set, int signum)
    该函数用于检查指定的信号是否在信号集合中。set 是要检查的信号集合的指针,signum 是要检查的信号编号。如果信号在信号集合中,返回1;如果信号不在信号集合中,返回0;如果发生错误,返回-1。

这些函数可以帮助我们方便地对信号集合进行操作,例如创建空的信号集合将所有信号添加到信号集合中从信号集合中删除特定的信号检查信号是否在信号集合中等。


🌧 以下是每个函数的用法示例

  1. int sigemptyset(sigset_t *set)
    该函数用于清空信号集合,将所有信号都设置为未包含状态。
#include <signal.h>

int main() {
    sigset_t set;
    sigemptyset(&set);  // 清空信号集合
    return 0;
}
  1. int sigfillset(sigset_t *set)
    该函数用于填充信号集合,将所有信号都设置为包含状态。
#include <signal.h>

int main() {
    sigset_t set;
    sigfillset(&set);  // 填充信号集合
    return 0;
}
  1. int sigaddset(sigset_t *set, int signum)
    该函数用于将指定的信号添加到信号集合中。
#include <signal.h>

int main() {
    sigset_t set;
    sigemptyset(&set);  // 清空信号集合
    sigaddset(&set, SIGINT);  // 将 SIGINT 信号添加到信号集合中
    return 0;
}
  1. int sigdelset(sigset_t *set, int signum)
    该函数用于从信号集合中删除指定的信号。
#include <signal.h>

int main() {
    sigset_t set;
    sigfillset(&set);  // 填充信号集合
    sigdelset(&set, SIGINT);  // 从信号集合中删除 SIGINT 信号
    return 0;
}
  1. int sigismember(const sigset_t *set, int signum)
    该函数用于检查指定的信号是否在信号集合中。
#include <signal.h>
#include <stdio.h>

int main() {
    sigset_t set;
    sigemptyset(&set);  // 清空信号集合
    sigaddset(&set, SIGINT);  // 将 SIGINT 信号添加到信号集合中

    if (sigismember(&set, SIGINT)) {
        printf("SIGINT is a member of the signal set\n");
    } else {
        printf("SIGINT is not a member of the signal set\n");
    }

    return 0;
}

sigaction函数

sigaction函数是用于设置和修改信号处理函数的系统调用。通过调用该函数,可以为特定的信号注册一个信号处理函数,并指定信号处理的行为。

sigaction函数的原型如下:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数说明:

  • signum:表示要注册的信号。
  • act:一个指向struct sigaction类型的指针,用于指定新的信号处理函数以及信号处理的行为。
  • oldact:一个指向struct sigaction类型的指针,用于保存之前的信号处理函数以及信号处理的行为。

函数返回值为0表示成功,返回-1表示出错。

下面是一个简单的示例程序,演示了如何使用sigaction函数:

#include <stdio.h>
#include <signal.h>

void handler(int sig)
{
    printf("Received signal %d\n", sig);
}

int main()
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGINT, &sa, NULL);

    while(1) {}

    return 0;
}

在这个示例程序中,首先定义了一个信号处理函数handler来处理 SIGINT 信号。然后创建了一个struct sigaction类型的结构体sa,并将其中的sa_handler成员设置为handler,其他成员设置为默认值。接着调用sigaction函数,为 SIGINT 信号注册了信号处理函数sa。

最后程序进入一个无限循环,等待 SIGINT 信号的到来。当进程收到 SIGINT 信号时,会调用事先注册的信号处理函数handler来处理该信号,并打印一些信息。

通过使用sigaction函数,可以为特定的信号注册一个信号处理函数,并指定信号处理的行为。与signal函数相比,sigaction函数提供了更多的灵活性和可靠性。

sigprocmask函数

sigprocmask函数是一个用于设置和修改进程信号屏蔽字的系统调用。通过调用该函数,可以控制进程对特定信号的处理方式。

sigprocmask函数的原型如下:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

参数说明:

  • how:表示如何修改信号屏蔽字的方式,可以取以下值:

    • SIG_BLOCK:将set中的信号添加到当前进程的信号屏蔽字中,即阻塞这些信号。(oldset原有的基础上添加新的信号屏蔽字)
    • SIG_UNBLOCK:从当前进程的信号屏蔽字中移除set中的信号,即解除对这些信号的阻塞。
    • SIG_SETMASK:将当前进程的信号屏蔽字设置为set中的值,即使用set中的信号屏蔽字替换当前进程的信号屏蔽字。
      在这里插入图片描述
  • set:一个指向sigset_t类型的指针,用于指定要修改的信号集合。

  • oldset:一个指向sigset_t类型的指针,用于保存之前的信号屏蔽字。

函数返回值为0表示成功,返回-1表示出错。

下面是一个简单的示例程序,演示了如何使用sigprocmask函数:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    printf("Received signal %d\n", sig);
}

int main()
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGINT, &sa, NULL);

    printf("Blocking SIGINT...\n");

    // 阻塞 SIGINT 信号
    sigset_t set, oldset;
    sigemptyset(&set);
     sigemptyset(&oldset);//先都清空
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, &oldset);

    printf("SIGINT is blocked. Sleeping for 10 seconds...\n");
    sleep(10);

    printf("Unblocking SIGINT...\n");

    // 解除对 SIGINT 信号的阻塞
    sigprocmask(SIG_SETMASK, &oldset, NULL);

    printf("SIGINT is unblocked. Sleeping for 10 seconds...\n");
    sleep(10);

    return 0;
}

在这个示例程序中,首先注册了一个信号处理函数handler来处理 SIGINT 信号。然后调用sigprocmask函数,将 SIGINT 信号添加到进程的信号屏蔽字中,即阻塞 SIGINT 信号。之后程序会打印一些信息,并休眠10秒钟。在这段时间内,如果进程收到 SIGINT 信号,则该信号会被暂时挂起,直到解除对该信号的阻塞。

接着,程序调用sigprocmask函数解除对 SIGINT 信号的阻塞,再次打印一些信息并休眠10秒钟。在这段时间内,如果进程收到 SIGINT 信号,则会调用事先注册的信号处理函数handler来处理该信号。

sigpending函数

sigpending函数用于获取当前进程未决的信号集,即已经发送但尚未被进程处理的信号集。

sigpending函数的原型如下:

int sigpending(sigset_t *set);

参数说明:

  • set:一个指向sigset_t类型的指针,用于保存未决信号集。

函数返回值为0表示成功,返回-1表示出错。

下面是一个简单的示例程序,演示了如何使用sigpending函数:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    printf("Received signal %d\n", sig);
}

int main()
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGUSR1, &sa, NULL);

    // 发送 SIGUSR1 信号
    printf("Sending SIGUSR1...\n");
    kill(getpid(), SIGUSR1);

    // 检查未决信号集
    sigset_t set;
    sigpending(&set);

    if (sigismember(&set, SIGUSR1)) {
        printf("SIGUSR1 is pending\n");
    } else {
        printf("SIGUSR1 is not pending\n");
    }

    return 0;
}

在这个示例程序中,首先定义了一个信号处理函数handler来处理 SIGUSR1 信号。然后创建了一个struct sigaction类型的结构体sa,并将其中的sa_handler成员设置为handler,其他成员设置为默认值。接着调用sigaction函数,为 SIGUSR1 信号注册了信号处理函数sa。

然后程序通过kill函数向当前进程发送了 SIGUSR1 信号。接着调用sigpending函数,获取当前进程的未决信号集,并将结果保存在set中。然后使用sigismember函数判断 SIGUSR1 是否在未决信号集中,如果是,则打印相应的信息。

通过使用sigpending函数,可以获取当前进程未决的信号集,即已经发送但尚未被进程处理的信号集。这对于需要了解当前进程是否收到某个信号以及是否处理了该信号非常有用。

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

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

相关文章

【MySQL】DQL的总结和案例学习

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-VWRkWqFrRMi4uLRa {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

华为自动驾驶干不过特斯拉?

文 | AUTO芯球 作者 | 李诞 什么&#xff1f; 华为的智能驾驶方案干不过蔚小理&#xff1f; 特斯拉的智能驾驶[FSD]要甩中国车企几条街&#xff1f; 这华为问界阿维塔刚刚推送“全国都能开”的城区“无图 NCA” 就有黑子来喷了 这是跪久了站不起来了吧 作为玩车14年&…

知识图谱概论

知识图谱 1 学习目标2 知识图谱概念2.1 什么是知识图谱2.2 语义网络2.3 知识图谱的定义 3 知识图谱的架构3.1 知识图谱的逻辑结构3.2 知识图谱的体系架构 4 知识图谱的关键技术4.1 信息抽取4.2 知识融合4.3 知识加工4.4 知识图谱存储4.5 知识更新 5 知识图谱的典型应用5.1 智能…

基于Bazel实现C++/Python编译

最近在学Baidu Apollo需要用到Bazel进行编译&#xff0c;在此记录下Bazel的学过程&#xff0c;以及遇到的一些问题和心得。另外强烈推荐B站赵虚左老师的Cyber RT课程&#xff0c;里面对Bazel的使用有详细的教学。 下面的使用过程都是在Ubuntu 22.04上进行的&#xff0c;首先需要…

Cassandra 命令大全

文章目录 1. 连接与基本操作2. 数据库管理3. 表&#xff08;Column Family&#xff09;操作4. 集群管理5. 权限管理6. 其他高级功能7. 条件查询与聚合操作8. 索引管理9. 用户权限和角色管理10. 安全性相关设置11. 一致性级别控制12. 用户定义类型 (UDTs)13. 用户定义函数 (UDFs…

2024年【天津市安全员C证】考试报名及天津市安全员C证免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年天津市安全员C证考试报名为正在备考天津市安全员C证操作证的学员准备的理论考试专题&#xff0c;每个月更新的天津市安全员C证免费试题祝您顺利通过天津市安全员C证考试。 1、【多选题】下列说法正确的是&#…

ChatGPT生产力|chat gpt实战介绍

标注说| ⭐ : 使用稳定&#xff0c;推荐 | &#x1f604; : 免费使用 | &#x1f511; : 需要登陆或密码 | ✈️ : 需waiwang进行访问 | ChatGPT 1PoePoe - Fast, Helpful ...&#x1f511;&#x1f604;&#x1f517;2 AItianhuGPT4&#x1f604;⭐&#x1f517;3 PhantoNa…

Vue ElementUI中el-table表格嵌套样式问题

一、表格嵌套要求&#xff1a; 两个表格嵌套&#xff0c;当父表格有children数组时子表格才展示&#xff1b;子表格数据少于父表格展示字段&#xff0c;且对应固定操作列不同&#xff1b; 二、嵌套问题&#xff1a; 当使用el-table的typeexpand实现表格嵌套时&#xff0c;样…

ChatGPT Plus如何升级?信用卡付款失败怎么办?如何使用信用卡升级 ChatGPT Plus?

ChatGPT Plus是OpenAI提供的一种高级服务&#xff0c;它相较于标准版本&#xff0c;提供了更快的响应速度、更强大的功能&#xff0c;并且用户可以优先体验到新推出的功能。 尽管许多用户愿意支付 20 美元的月费来订阅 GPT-4&#xff0c;但在实际支付过程中&#xff0c;特别是…

(2)(2.13) Rockblock Satellite Modem

文章目录 前言 1 支持的MAVLink命令信息 2 设置 3 使用方法 4 数据成本 5 参数 前言 &#xff01;Note 该功能仅适用于 ArduPilot 4.4 或更高版本&#xff0c;并且要求飞行控制器支持 LUA 脚本(LUA Scripts)。 RockBLOCK 卫星调制解调器可实现与 ArduPilot 飞行器的全球…

【MySQL】- 09 Select Count

【MySQL】- 09 Select Count 1认识COUNT2 COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别3 COUNT(*)的优化 4 COUNT(*)和COUNT(1)5 COUNT(字段)总结 数据库查询相信很多人都不陌生&#xff0c;所有经常有人调侃程序员就是CRUD专员&#xff0c;这所谓的CRUD指的就是数据库的增删…

[python] 过年燃放烟花

目录 新年祝福语 一、作品展示 二、作品所用资源 三、代码与资源说明 四、代码库 五、完整代码 六、总结 新年祝福语 岁月总是悄然流转&#xff0c;让人感叹时间的飞逝&#xff0c;转眼间又快到了中国传统的新年&#xff08;龙年&#xff09;。 回首过去&#xf…

VMWare下载安装(包含Window是和Mac)

VMWare下载安装&#xff08;包含Window是和Mac&#xff09; 文章目录 VMWare下载安装&#xff08;包含Window是和Mac&#xff09;一、windows下载VMWare①&#xff1a;下载01&#xff1a;网盘下载02&#xff1a;官方下载 ②&#xff1a;安装③&#xff1a;密钥 二、Mac下载VMWa…

2.3作业

作业要求&#xff1a; 程序代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h> typedef struct node //定义链表节点结构体&#xff1a;数据域、指针域 {int data;struct node *next; }*linklist;linklist create_node()//创建新节…

【解刊】顶级IEEE(trans),一审极快!对国人审稿友好,大咖教授投稿之选

计算机类 • 高分快刊 今天带来IEEE旗下计算机领域高分快刊&#xff0c;审稿速度快&#xff0c;期刊质量高&#xff0c;审稿过程友好。如有投稿意向可重点关注&#xff1a; 01 期刊简介 IEEE Transactions on Network Science and Engineering ✅出版社&#xff1a;IEEE ✅I…

缓存组件Caffeine的使用

caffeine是一个高性能的缓存组件&#xff0c;在需要缓存数据&#xff0c;但数据量不算太大&#xff0c;不想引入redis的时候&#xff0c;caffeine就是一个不错的选择。可以把caffeine理解为一个简单的redis。 1、导入依赖 <!-- https://mvnrepository.com/artifact/com.git…

力扣题目训练(7)

2024年1月31日力扣题目训练 2024年1月31日力扣题目训练387. 字符串中的第一个唯一字符389. 找不同401. 二进制手表109. 有序链表转换二叉搜索树114. 二叉树展开为链表52. N 皇后 II 2024年1月31日力扣题目训练 2024年1月31日第七天编程训练&#xff0c;今天主要是进行一些题训…

小型内衣洗衣机什么牌子好?家用小型洗衣机推荐

内衣裤作为我们日常必备的贴身衣物&#xff0c;所以对卫生方面的要求也比较高&#xff0c;但对许多人们而言&#xff0c;对内衣裤进行清洗是一项相当繁琐的事情&#xff0c;主要是因为并不能直接把内衣裤放入大型洗衣机里和其它衣服混合洗&#xff0c;所以大多数用户都会自己动…

2024美赛数学建模C题完整论文教学(含十几个处理后数据表格及python代码)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了数学建模美赛本次C题目Momentum in Tennis完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 C论文共49页&…

程序员想告赢开发商一户一表违约(终审判决)——铁拳迟到会打到每一个人...

二审的结果并没有出乎我的意料&#xff1a;维持原判。所以是我输了这场官司。 只是我输得非常不服气。 在二审中&#xff0c;我变换思路&#xff0c;以以下思路进行辩论&#xff1a; 1. 从“正式供电”方向&#xff0c;使用国家国标和法律法规证明小区目前非正式用电&#xff0…