嵌入式Linux系统编程 — 6.6 信号掩码

目录

1 信号掩码介绍

2 sigprocmas函数

3 sigsuspend函数阻塞等待信号


1 信号掩码介绍

信号掩码(Signal Mask)是操作系统中用于控制进程接收信号的一种机制。每个进程都有一个或多个信号掩码,它们定义了哪些信号在特定时间被阻塞(即暂时忽略),哪些信号可以被进程接收。

向信号掩码中添加一个信号,通常有如下几种方式:

  • 当应用程序调用 signal()或 sigaction()函数为某一个信号设置处理方式时,进程会自动将该信号添加到信号掩码中, 这样保证了在处理一个给定的信号时,如果此信号再次发生,那么它将会被阻塞;对于 sigaction(),需要根据 sigaction()函数是否设置了 SA_NODEFER 标志决定该信号添加到信号掩码中;当信号处理函数结束返回后,会自动将该信号从信号掩码中移除。
  • 使用 sigaction()函数为信号设置处理方式时,可通过 sa_mask 参数进行设置该组信号是否自动添加到信号掩码中。
  • 除了以上两种方式之外,还可以使用 sigprocmask()系统调用,随时可以显式地向信号掩码中添加/移除信号。

2 sigprocmas函数

sigprocmask() 函数用于管理进程的信号屏蔽字(signal mask),即控制哪些信号可以被进程接收,哪些信号被暂时阻塞。函数原型如下所示:

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • how:指定了如何修改信号屏蔽字,可以是以下宏之一:

    • SIG_BLOCK:将 set 指向的信号集中的信号添加到当前信号屏蔽字中。
    • SIG_UNBLOCK:将 set 指向的信号集中的信号从当前信号屏蔽字中移除。
    • SIG_SETMASK:将当前信号屏蔽字设置为 set 指向的信号集。
  • set:指向 sigset_t 结构的指针,该结构定义了一组信号,根据 how 参数的值,这些信号将被添加到、移除或设置为当前的信号屏蔽字。

  • oldset:如果非空,sigprocmask() 将当前的信号屏蔽字存储在 oldset 指向的 sigset_t 结构中。

  • 返回值:成功时返回 0,失败时返回 -1,并设置 errno 以指示错误。

以下是使用 sigprocmask() 的示例代码:

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

int main() 
{
    sigset_t set, oldset, pending;

    // 将SIGINT添加到信号集中
    sigemptyset(&set);
    sigaddset(&set, SIGINT);

    // 阻塞SIGINT信号
    if (sigprocmask(SIG_BLOCK, &set, &oldset) < 0) {
        perror("sigprocmask SIG_BLOCK");
        return 1;
    }

    // ... 执行其他任务,SIGINT信号被阻塞 ...

    // 检查SIGINT是否在待处理信号集中
    sigpending(&pending);
    if (sigismember(&pending, SIGINT)) {
        printf("SIGINT is pending.\n");
    }

    // 恢复原始信号掩码
    if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) {
        perror("sigprocmask SIG_SETMASK");
        return 1;
    }

    printf("SIGINT is no longer blocked.\n");

    return 0;
}

程序首先创建并初始化了一个信号集 set,然后将 SIGINT 信号添加到这个信号集中。接着使用 sigprocmask() 函数调用,通过 SIG_BLOCK 选项来阻塞 SIGINT 信号,并保存旧的信号掩码到 oldset 中。之后,使用 sigpending() 函数来检查 SIGINT 是否在待处理信号集中。最后,我们使用 sigprocmask() 函数调用,通过 SIG_SETMASK 选项来恢复原始的信号掩码,从而解除对 SIGINT 信号的阻塞。运行结果如下:

3 sigsuspend函数阻塞等待信号

sigsuspend() 函数会替换当前进程的信号掩码为函数参数sigmask 指向的信号掩码,并立即挂起调用进程的执行。进程会一直挂起直到有信号到达,并且该信号不在当前的信号屏蔽字中,或者有信号被 sigpending() 函数标记为“待处理”。当信号被处理后,进程恢复执行,并恢复到之前的信号掩码。

可以用一句话进行理解,暂停当前进程直到有指定信号掩码之外的信号触发处理完成。函数原型如下所示:

#include <signal.h>

int sigsuspend(const sigset_t *mask);
  • mask: 参数 mask 指向一个信号集。
  • 返回值: sigsuspend()始终返回-1,并设置 errno 来指示错误(通常为 EINTR) ,表示被信号所中断,如果调用失败,将 errno 设置为 EFAULT。

调用 sigsuspend()函数相当于以不可中断的方式执行以下操作:

sigprocmask(SIG_SETMASK, &mask, &old_mask);
pause();
sigprocmask(SIG_SETMASK, &old_mask, NULL);

通过下面的的程序来理解函数,以下是使用 sigsuspend() 的示例代码:

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

// 静态信号处理函数定义
static void sig_handler(int sig) {
    printf("执行信号处理函数...\n");
}

int main(void) {
    struct sigaction sa; // 使用更简洁的变量名
    sigset_t new_mask, old_mask, wait_mask;

    /* 初始化信号集 */
    sigemptyset(&new_mask);
    sigaddset(&new_mask, SIGINT);
    sigemptyset(&wait_mask); // 这里可以不用再次初始化,因为sigsuspend不会修改wait_mask

    /* 注册信号处理函数 */
    sa.sa_handler = sig_handler;
    sa.sa_flags = 0;
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    /* 向信号掩码中添加信号 */
    if (sigprocmask(SIG_BLOCK, &new_mask, &old_mask) == -1) {
        perror("sigprocmask");
        exit(EXIT_FAILURE);
    }

    /* 执行保护代码段 */
    puts("执行保护代码段");

    /* 挂起、等待信号唤醒 */
    // sigsuspend的返回值检查可以省略,因为标准行为是永远不返回
    sigsuspend(&wait_mask);

    /* 恢复信号掩码 */
    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
        perror("sigprocmask");
        exit(EXIT_FAILURE);
    }

    // 正常退出程序
    return 0;
}

程序首先声明一个静态的信号处理函数 sig_handler,该函数在接收到信号时被调用,并打印一条消息。在 main 函数中,程序初始化了三个信号集:

  • new_mask 用于定义需要被阻塞的信号,
  • old_mask 用于存储当前的信号掩码,
  • wait_mask 用作 sigsuspend 的参数。

使用 sigaction 函数注册了 sig_handler 函数来处理 SIGINT 信号。然后,程序通过 sigprocmask 函数设置 new_mask 为当前信号掩码,以阻塞 SIGINT 信号。接下来,程序执行一个保护代码段,之后调用 sigsuspend 挂起,直到接收到 SIGINT 信号。一旦信号到达,sig_handler 函数被执行,然后程序从 sigsuspend 返回并恢复原始的信号掩码,最后正常退出。 


 

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

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

相关文章

2024年在WordPress中创建销售活动的专家级优惠券方法

2024年在WordPress中创建销售活动的专家级优惠券方法 今天我想和大家分享一些关于如何在WordPress网站上使用专家级优惠券工具来创建销售活动的经验。对于已经在电商领域有一定经验的店主&#xff0c;利用专家级优惠券不仅能吸引顾客&#xff0c;还能显著增加销量。在这篇文章…

地铁车厢火灾3D模拟逃生演习减少了资源损耗和风险

在消防安全领域&#xff0c;为了更好地提升安全实训效果&#xff0c;我们在VR安全培训领域打造了多款消防安全VR模拟实训系统&#xff0c;不仅实现了与现实世界无异的交互操作&#xff0c;更在虚拟空间中超越了现实的限制&#xff0c;模拟出那些现实中难以搭建的复杂场景。 利用…

The Sandbox 创作者的幕后采访: 了解创作者的内心世界

我们采访了一些在 "创作者挑战" 中脱颖而出的顶尖创作者&#xff0c;探讨他们成功的秘诀以及在创造玩家喜爱的体验方面的心得。 The Sandbox 创作者挑战涌现出许多才华横溢的创作者&#xff0c;他们在游戏制作机制上的创新和突破引起了 The Sandbox 社区的广泛关注。…

Java数据结构面试题(一)

目录 一.ArrayList和LinkedList的区别 二.ArrayList和Vector的区别 三.HashMap的底层实现 四.HashMap和ConcurrentHashMap的区别 五.HashMap和HashTable的区别 六.多线程的情况下使用HashMap呢&#xff1f; 七.HashMap的如何扩容呢&#xff1f; 八.哈希冲突 本专栏全是…

Mac/Linux安装JMeter压测工具

Mac安装JMeter压测工具 介绍 Apache JMeter™应用程序是开源软件&#xff0c;是一个100%纯的Java应用程序&#xff0c;旨在加载测试功能行为和衡量性能。它最初是为测试Web应用程序而设计的&#xff0c;但后来扩展到其他测试功能。 我能用它做什么&#xff1f; Apache JMet…

VCL界面组件DevExpress VCL v24.1 - 发布全新的矢量主题

DevExpress VCL是DevExpress公司旗下最老牌的用户界面套包&#xff0c;所包含的控件有&#xff1a;数据录入、图表、数据分析、导航、布局等。该控件能帮助您创建优异的用户体验&#xff0c;提供高影响力的业务解决方案&#xff0c;并利用您现有的VCL技能为未来构建下一代应用程…

起飞,纯本地实时语音转文字!

简介 偶然在 github 上翻到了这个项目 https://github.com/k2-fsa/sherpa-ncnn 在没有互联网连接的情况下使用带有 ncnn 的下一代 Kaldi 进行实时语音识别。支持 iOS、Android、Raspberry Pi、VisionFive2、LicheePi4A等。 也就是说语音转文字可以不再借助网络服务的接口&am…

桂花网蓝牙网关X1000:引领物联网新时代的智能连接

在物联网技术飞速发展的今天&#xff0c;蓝牙网关作为连接蓝牙设备与互联网的关键设备&#xff0c;其性能与稳定性直接影响到物联网系统的整体运行效果。桂花网蓝牙网关X1000凭借其卓越的性能和广泛的应用场景&#xff0c;成为了物联网领域的佼佼者。 一、产品概述 桂花网蓝牙…

fastadmin最新版导出数据时 表格中会有 html标签的解决办法

fastadmin 自带的导出方法, 是一个纯前端的导出, 没有请求后台的接口 当我们使用导出功能时, 有些数据, 我们在设计的时候,配置的是 枚举类型的 但是当我们导出数据的时候, 居然导出的数据中带有 html 的标签 上面的情况我们的解决办法是,在导出的时候,把html 的标签…

mongdb学习与使用

1. 基础概念 MongoDB简介&#xff1a; MongoDB是一个基于文档的NoSQL数据库&#xff0c;具有高性能、高可用性和易扩展性。数据存储在类似JSON的BSON格式中。 基本术语&#xff1a; Database&#xff08;数据库&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…

C++必修:深入理解继承与虚继承

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. 继承的概念与定义 1.1. 继承的概念 继承(inheritance)机制是面向对象程序设计…

每日一题——Python实现PAT乙级1018 锤子剪刀布(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码结构与逻辑 时间复杂度分析 空间复杂度分析 代码优化建议 总结 我…

【java计算机毕设】美容院管理系统 项目源代码MySQL springboot vue html maven+文档 前后端可分离也可不分离

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】美容院管理系统 项目源代码MySQL springboot vue html maven文档 前后端可分离也可不分离 2项目介绍 系统功能&#xff1a; 美容院管理系统包括管理员、用户俩种角色。 管理员功能包括个人中心模块用于修改…

“论单元测试方法及应用”精选范文,软考高级论文,系统架构设计师论文

论文真题 1、概要叙述你参与管理和开发的软件项目,以吸你所担的主要工作。 2、结给你参与管理和开发的软件项目&#xff0c;简要叙述单元测试中静态测试和动态测试方法的基本内容。 3、结给你惨与管理和研发的软件项目,体阐述在玩测试过程中,如何确定白盒测试的覆盖标准,及如…

【C语言】sizeof 关键字

在C语言中&#xff0c;sizeof运算符用于计算数据类型或变量的大小&#xff08;以字节为单位&#xff09;。sizeof是一个编译时运算符&#xff0c;它在编译阶段确定类型或变量的大小&#xff0c;而不是在运行时。 基本用法 sizeof可以用于计算基本数据类型、数组、结构体以及指…

银湖资本与UIBE达成战略合作,共同推动股权投资领域发展

近日&#xff0c;全球知名私募股权投资公司银湖资本&#xff08;Silver Lake Partners&#xff09;宣布与对外经济贸易大学&#xff08;UIBE&#xff09;校友发起的“UIBE阿波罗股权投资俱乐部”达成战略合作协议。此举不仅标志着双方在股权投资领域的深度合作&#xff0c;也为…

LVS-DR负载均衡

LVS-DR负载均衡 LVS—DR工作模式 原理 客户端访问调度器的VIP地址&#xff0c;在路由器上应该设置VIP跟调度器的一对一的映射关系&#xff0c;调度器根据调度算法将该请求“调度“到后端真实服务器&#xff0c;真实服务器处理完毕后直接将处理后的应答报文发送给路由器&#xf…

使用 draw.io 画图

尽管我非常喜欢 wps 和 office 的 ppt 画图&#xff0c;但因为它们对数学公式的糟糕支持&#xff0c;我不得不另外寻找一个画图工具。当然我也同样很喜欢 visio &#xff0c;但同样的&#xff0c;它对数学公式的支持糟糕&#xff0c;另外&#xff0c;最为重要的是&#xff0c;v…

不同的llm推理框架

vLLM适用于大批量Prompt输入&#xff0c;并对推理速度要求比较高的场景。 实际应用场景中&#xff0c;TensorRT-LLM通常与Triton Inference Server结合起来使用&#xff0c;NVIDIA官方能够提供更适合NVIDIA GPU运行的高效Kernel。 LightLLM比较轻量、易于扩展、易于上手&…

Android 抓取 CPU 资源信息

在 Android 开发中&#xff0c;使用 ADB&#xff08;Android Debug Bridge&#xff09;命令获取 CPU 资源信息有很多重要的作用。这些命令可以帮助开发者在多种情况下分析和优化应用性能、解决问题以及进行系统性调试。 以下列举一些 ABD 获取 CPU 资源信息的命令 获取 CPU 核…