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

news2024/10/6 10:29:12

目录

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 返回并恢复原始的信号掩码,最后正常退出。 


 

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

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

相关文章

探索中文文本之美:使用Python生成定制化词云

探索中文文本之美&#xff1a;使用Python生成定制化词云 数据可视化已成为我们理解复杂信息的关键工具。词云&#xff0c;作为一种流行的数据可视化形式&#xff0c;能够将大量文本数据中的关键词以视觉化的方式呈现&#xff0c;让我们迅速捕捉到文本的核心。本文将通过Python…

麒麟V10安装MinIO

1、官网下载服务端程序 2、上传至/usr/local/bin/&#xff0c;使用官网命令启动 chmod x minio MINIO_ROOT_USERadmin MINIO_ROOT_PASSWORDpassword ./minio server /mnt/data --console-address ":9001"后台启动 MINIO_ROOT_USERadmin MINIO_ROOT_PASSWORDpassw…

【Python好书推荐】,学习Python必备的8本书,可分享电子档!

在过去一年里&#xff0c;Python的热度一路飙升&#xff0c;国内越来越多的人选择学习Python&#xff0c;如今已然成为大量开发者推荐的入门编程语言和第二编程语言&#xff0c;而且Python还是人工智能的主要编程语言&#xff0c;因此&#xff0c;其重要性和流行度也就不言而喻…

最新榜单出炉!2024年6月AI行业微信公众号排行榜

最新榜单出炉&#xff01;2024年6月AI行业微信公众号排行榜 &#x1f680; 大家好&#xff0c;我是猫头虎&#xff01;最新的AIGCRank AI行业微信公众号排行榜已经出炉了。如果大家觉得一个一个去搜索太麻烦&#xff0c;没关系&#xff0c;我帮大家整理到了本文&#xff0c;今…

代谢组数据分析(十三):评估影响代谢物的重要临床指标

欢迎大家关注全网生信学习者系列: WX公zhong号:生信学习者Xiao hong书:生信学习者知hu:生信学习者CDSN:生信学习者2介绍 相关性分析是通过计算两个变量之间的相关系数来评估它们之间线性关系的强度和方向。最常用的是皮尔逊相关系数(Pearson correlation coefficient),…

Appium自动化测试框架1

电脑的浏览器 手机的浏览器 手机上的app 原生的应用 纯java 手机上的app apk 移动网页应用 纯HTML CSS 手机的浏览器上 电脑的浏览器上 混合应用 java html css python代码 Appium python库 Appium 手机 都是代表本机 0.0.0.0 127.0.0.1 localhost 如何启动app 启动参…

数据结构 1.1 数据结构的基本概念

本章总览&#xff1a; 一.什么是数据 1.数据 数据是信息的载体&#xff0c;是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程 序识别和处理的符号的集合。数据是计算机程序加工的原料。 早期计算机只能处理纯数值的问题&#xff0c;如世界第一题计算机ENI…

绩效管理,不再只是一串数字!

在数字化转型的大潮中&#xff0c;绩效管理不再只是枯燥的数字统计。搭贝的绩效管理系统&#xff0c;为企业提供灵活多样的考核模式与工具&#xff0c;助力实现科学、高效的管理。无论是KPI&#xff08;关键绩效指标&#xff09;还是OKR&#xff08;目标与关键成果&#xff09;…

2024年第十四届APMCM亚太地区大学生数学建模竞赛

C 题 基于量子计算的物流配送问题 随着电子商务的迅猛发展&#xff0c;电商平台对物流配送的需求日益增长。为了确保货物能够按时、高效地送达消费者手中&#xff0c;电商平台与第三方物流公司建立了紧密的合作关系。然而&#xff0c;面对大量的货物和多样的目的地&#xff0c…

一篇轻易入门Pandoc库实现文档格式自由转换

目录 Pandoc库概述: 安装Pandoc工具: 安装pypandoc库: 示例 特点 核心优势 局限性 功能和使用场景 高级功能及示例 总结 如果您需要将文件从一种标记格式转换为另一种标记格式&#xff0c;pandoc 就是您的瑞士军刀.Pandoc 可以在以下格式之间进行转换一款转换神奇. …

如何使用小红书矩阵系统:提升内容管理与发布效率的指南

小红书作为一个流行的社交电商平台&#xff0c;吸引了大量的内容创作者和品牌入驻。为了更高效地管理内容和提升用户体验&#xff0c;小红书矩阵系统提供了一套强大的工具和功能。本文将详细介绍如何使用小红书矩阵系统&#xff0c;帮助您最大化利用其核心功能。 小红书矩阵系…

datawhale大模型应用开发夏令营学习笔记一

参考自 基于LangChainLLM的本地知识库问答&#xff1a;从企业单文档问答到批量文档问答datawhale的llm-universe 作者现在在datawhale夏令营的大模型应用开发这个班中&#xff0c;作为一个小白&#xff0c;为了能为团队做出一点贡献&#xff0c;现在就要开始学习怎么使用langch…

地下电子标识器探测仪ED8000选型注意事项

ED8000探测仪是一台集成了多频率、多种ID标识器调制模式、高低灵敏度调节、可读写标识器等全功能、高性能电子标识器探测仪。它有着极高的灵敏度,同时具备良好的噪声抑制能力&#xff0c;不仅适合专业测绘人员&#xff0c;普通操作人员也可以轻松掌握。 ED8000可支持模拟电子标…

Android10以上实现获取设备序列号功能

Android10以上实现获取设备唯一标识&#xff0c;目前只支持华为和荣耀设备。实现原理&#xff1a;通过无障碍服务读取序列号界面。 public class DeviceHelper implements Application.ActivityLifecycleCallbacks {static final String TAG "WADQ_DeviceHelper";s…

【ubuntu自启shell脚本】——在ubuntu中如何使用系统自带的启动应用程序设置开机自启自己的本地shell脚本

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、设置开机自启shell脚本1.使用 gnome-session-properties2.测试的shell例程代码 总结 前言 在Ubuntu系统中设置开机自启脚本是一种重要的自动化方法。开机自…

基于docker轻松部署selenium grid环境

做web自动化的同学都知道selenium grid非常好用&#xff0c;但是环境配置特别麻烦&#xff0c;很多人都躺在了环境搭建。那么有没有更简单的方式呢&#xff0c;答案是肯定的&#xff0c;今天我们就用docker来完成它&#xff0c;希望对大家有帮助。 一、环境准备 准备一台 Linu…

《安全大模型技术与市场研究报告》发布,海云安榜上有名

近日&#xff0c;网络安全产业研究机构“数说安全”发布2024《安全大模型技术与市场研究报告》&#xff08;以下简称“报告”&#xff09;。 海云安凭借在开发安全领域的优秀业务能力以及在大模型相关技术研究方面的成就得到了认可&#xff0c;入选“安全开发大模型推荐供应商”…

实现点击Button,改变背景颜色(多个按钮互斥显示)

一 功能描述 在界面中&#xff0c;有一组button&#xff0c;现在需要实现下面功能&#xff1a;点击其中一个&#xff0c;改变被点击button的背景颜色。当点击下一个之后&#xff0c;之前点击过的按钮背景颜色还原&#xff0c;当前被点击的button背景色又被改变。效果如下图&…

PowerDsigner的简单使用

目录 1.PowerDesinger 2.PD与navicat的区别&#xff1a; 3.使用 1.PowerDesinger 在实际开发中&#xff0c;数据库的设计会使用专业的建模工具——PowerDesinger &#xff08;安装及其破解大家搜选相关CSDN博客吧&#xff09; 2.PD与navicat的区别&#xff1a; navicat是…

Zabbix企业级监控系统

——监控可以帮助我们做什么&#xff1f; 作为一个运维&#xff0c;需要会使用监控系统查看服务器系统性能、应用服务状态和网站流量指标等&#xff0c;利用监控系统的数据去了解网站上线发布的结果和健康状态。 利用一个优秀的监控软件&#xff0c;我们可以: 通过一个友好的…