Linux系统编程之高级信号处理

news2025/2/24 0:42:16

概述

        在前一篇文章中,我们介绍了signal函数、sigaction函数等基本的信号处理方法。在本篇中,我们将介绍信号处理的一些高级用法,包括:阻塞与解除阻塞、定时器等。

阻塞与解除阻塞

        有时候,我们不希望某个信号立即被处理,而是暂时将其阻塞起来。此时,可以使用sigprocmask函数来修改当前进程的信号掩码,从而达到阻塞或解除阻塞的效果,这对于确保多线程环境中信号的安全处理非常重要。

        sigprocmask函数的原型如下。

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

        各个参数和返回值的含义如下。

        how:决定了如何修改信号掩码,必须是以下三个宏之一。

        (1)SIG_BLOCK:新的信号集将被添加到当前的信号掩码中,即这些信号将会被阻塞。

        (2)SIG_UNBLOCK:新的信号集中的信号将从当前的信号掩码中移除,即这些信号将不再被阻塞。

        (3)SIG_SETMASK:当前的信号掩码将被新的信号集完全替换。

        set:指向sigset_t类型的指针,这个集合包含了要修改的信号。如果为NULL,则不会修改信号掩码,但oldset将包含当前的信号掩码。

        oldset:如果不是NULL,它指向的对象将被设置为函数调用之前的信号掩码。这可以用来保存当前的信号掩码,以便之后恢复。

        返回值:成功时返回0,失败时返回-1,并设置errno以指示具体的错误原因。

        sigset_t是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。若出错,则返回-1。

        在下面的示例代码中,我们先阻塞了SIGINT信号,然后对SIGINT信号解除了阻塞。

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

void BlockSignal(int signum)
{
    sigset_t set;、
    // 初始化信号集为空
    sigemptyset(&set);
    // 添加信号到集合
    sigaddset(&set, signum);
    sigprocmask(SIG_BLOCK, &set, NULL);
}

void UnblockSignal(int signum)
{
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, signum);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
}

int main()
{
    int signum = SIGINT;
    BlockSignal(signum);
    printf("Signal %d is now blocked\n", signum);

    // 其他代码...

    UnblockSignal(signum);
    printf("Signal %d is now unblocked\n", signum);
    return 0;
}

定时器

        SIGALRM是Linux系统中的一个信号,用于通知进程定时器到期。当使用alarm函数或setitimer函数设置的定时器超时时,系统便会向进程发送SIGALRM信号。

        1、alarm函数。设置一个一次性的计时器,在指定的秒数后,会发送SIGALRM给进程。

unsigned int alarm(unsigned int seconds);

        各个参数和返回值的含义如下。

        seconds:希望在多少秒后接收到SIGALRM信号的时间间隔。如果为零,则不会安排新的SIGALRM信号,并且任何之前设置的未决SIGALRM信号都会被取消。

        返回值:如果之前已经设置了定时器,会返回剩余到前一个定时器触发的时间,以秒为单位。如果没有之前的定时器,它将返回0。

        2、setitimer函数。提供更细粒度的控制,可以设置间隔定时器,指定不同的定时器类型,并且可以配置为周期性触发。

int setitimer(int which, const struct itimerval *new_value, 
    struct itimerval *old_value);

        各个参数和返回值的含义如下。

        which:指定要设置的定时器类型,可取的值如下。

        (1)ITIMER_REAL:发送SIGALRM信号时,基于实际墙钟时间。

        (2)ITIMER_VIRTUAL:当进程执行时发送SIGVTALRM信号,只计算用户模式下的CPU时间。

        (3)ITIMER_PROF:当进程执行或在系统调用中,等待时发送SIGPROF信号,用于性能分析,既计算用户模式又计算内核模式下的CPU时间。

        new_value:指向itimerval结构体的指针,定义了新的定时器值。这个结构体包含两个timeval结构体成员。

        (1)it_value:下次定时器到期前的时间量。当这个值达到零时,定时器将被触发,并根据it_interval重新加载。

        (2)it_interval:定时器到期后的重装值,即每次触发后重新开始计时的时间间隔。如果为零,则定时器仅触发一次。

        old_value:如果不是NULL,则指向itimerval结构体,用来保存之前的定时器设置。

        返回值:成功时返回0,失败时返回-1,并设置errno以指示具体的错误原因。

        默认情况下,接收到SIGALRM信号会导致进程终止。我们可以通过调用signal或sigaction函数来安装自定义的信号处理程序,从而改变这种行为。

        在下面的示例代码中,我们首先设置了SIGALRM信号的处理器。然后,使用alarm函数来设定一个6秒的定时器。当定时器到期时,SIGALRM信号被发送给进程,我们的自定义处理器将会被调用。之后,程序将继续执行。

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

void OnHandleAlarm(int signum)
{
    if (signum == SIGALRM)
    {
        printf("Alarm signal received\n");
    }
}

int main()
{
    // 安装SIGALRM信号处理器
    if (signal(SIGALRM, OnHandleAlarm) == SIG_ERR)
    {
        printf("signal failed\n");
        exit(EXIT_FAILURE);
    }

    // 设置一个6秒的定时器
    alarm(6);

    printf("Waiting for the alarm...\n");
    // 暂停,直到接收到信号
    pause();

    printf("Program continues after alarm\n");
    return 0;
}

        如果需要更高精度的时间间隔,或希望定时器能够重复触发,可以使用setitimer函数代替alarm函数。在接下来的示例代码中,我们设置了SIGALRM信号处理器,并通过setitimer函数配置了一个定时器。该定时器会在1秒后首次触发,然后每隔1秒再次触发。每当定时器到期时,OnHandleAlarm函数就会被执行。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>

void OnHandleAlarm(int signum)
{
    if (signum == SIGALRM)
    {
        printf("Timer expired\n");
    }
}

int main()
{
    // 设置SIGALRM的处理函数
    signal(SIGALRM, OnHandleAlarm);

    // 配置定时器:首次触发时间为1秒,之后每隔1秒触发一次
    struct itimerval timer;
    // 第一次触发的时间
    timer.it_value.tv_sec = 1;
    timer.it_value.tv_usec = 0;
    // 每次触发后,重新开始计时的时间间隔
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;

    // 设置ITIMER_REAL定时器
    setitimer(ITIMER_REAL, &timer, NULL);

    printf("Waiting for the timer...\n");
    // 让程序持续运行,并响应定时器信号
    while(1)
    {
        pause();
    }

    return 0;
}

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

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

相关文章

Ollama 本地GUI客户端:为DeepSeek用户量身定制的智能模型管理与交互工具

Ollama 本地GUI客户端&#xff1a;为DeepSeek用户量身定制的智能模型管理与交互工具 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例&#xf…

基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘 要 《计算机网络》题库管理系统是一种新颖的考试管理模式&#xff0c;因为系统是用Java技术进行开发。系统分为三个用户进行登录并操作&#xff0c;分别是管理员、教师和学生。教师在系统后台新增试题和试卷&#xff0c;学生进行在线考试&#xff0c;还能对考生记录、错题…

对Revit事务机制的一些推测

什么是事务机制 首先&#xff0c;什么是事务机制。软件事务机制是指一种在软件系统中用于管理一系列操作的方法&#xff0c;这些操作要么全部成功完成&#xff0c;要么全部失败&#xff0c;不会出现部分完成的情况。事务机制确保了数据的一致性和完整性&#xff0c;特别是在并…

《微软量子芯片:开启量子计算新纪元》:此文为AI自动生成

量子计算的神秘面纱 在科技飞速发展的今天,量子计算作为前沿领域,正逐渐走进大众的视野。它宛如一把神秘的钥匙,有望开启未来科技变革的大门,而微软量子芯片则是这把钥匙上一颗璀璨的明珠。 量子计算,简单来说,是一种遵循量子力学规律调控量子信息单元进行计算的新型计算…

SpringBoot+Vue+Mysql苍穹外卖

一.项目介绍 1.项目内容 苍穹外卖是一款为大学学子设计的校园外卖服务软件&#xff0c;旨在提供便捷的食堂外卖送至宿舍的服务。该软件包含系统管理后台和用户端&#xff08;微信小程序&#xff09;两部分&#xff0c;支持在线浏览菜品、添加购物车、下单等功能&#xff0c;并…

网络运维学习笔记 018 HCIA-Datacom综合实验02

文章目录 综合实验2sw3&#xff1a;sw4&#xff1a;gw&#xff1a;core1&#xff08;sw1&#xff09;&#xff1a;core2&#xff08;sw2&#xff09;&#xff1a;ISP 综合实验2 sw3&#xff1a; vlan 2 stp mode stp int e0/0/1 port link-type trunk port trunk allow-pass v…

QT 引入Quazip和Zlib源码工程到项目中,无需编译成库,跨平台,压缩进度

前言 最近在做项目时遇到一个需求&#xff0c;需要将升级的文件压缩成zip&#xff0c;再进行传输&#xff1b; 通过网络调研&#xff0c;有许多方式可以实现&#xff0c;例如QT私有模块的ZipReader、QZipWriter&#xff1b;或者第三方库zlib或者libzip或者quazip等&#xff1…

车载诊断架构 --- LIN节点路由转发注意事项

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

Eclipse2024中文汉化教程(图文版)

对应Eclipse,部分人需要中文汉化,本章教程,介绍如何对Eclipse进行汉化的具体步骤。 一、汉化前的Eclipse 默认安装Eclipse的时候,默认一般都是English的,我当前版本是使用的是2024-06版本的Eclipse。 二、汉化详细步骤 点击上方菜单选项卡,Hep——Install New Software……

医院安全(不良)事件上报系统源码,基于Laravel8开发,依托其优雅的语法与强大的扩展能力

医院安全&#xff08;不良&#xff09;事件上报系统源码 系统定义&#xff1a; 规范医院安全&#xff08;不良&#xff09;事件的主动报告&#xff0c;增强风险防范意识&#xff0c;及时发现医院不良事件和安全隐患&#xff0c;将获取的医院安全信息进行分析反馈&#xff0c;…

【第一节】C++设计模式(创建型模式)-工厂模式

目录 前言 一、面向对象的两类对象创建问题 二、解决问题 三、工厂模式代码示例 四、工厂模式的核心功能 五、工厂模式的应用场景 六、工厂模式的实现与结构 七、工厂模式的优缺点 八、工厂模式的扩展与优化 九、总结 前言 在面向对象系统设计中&#xff0c;开发者常…

爬虫小案例豆瓣电影top250(json格式)

1.json格式&#xff08;仅供学习参考&#xff09; import requests, json, jsonpathclass Start(object):# 类实例化时会执行def __init__(self):self.headers {user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.…

Spring事务原理 二

在上一篇博文《Spring事务原理 一》中&#xff0c;我们熟悉了Spring声明式事务的AOP原理&#xff0c;以及事务执行的大体流程。 本文中&#xff0c;介绍了Spring事务的核心组件、传播行为的源码实现。下一篇中&#xff0c;我们将结合案例&#xff0c;来讲解实战中有关事务的易…

SpringAI系列 - ToolCalling篇(二) - 如何设置应用侧工具参数ToolContext(有坑)

目录 一、引言二、集成ToolContext示例步骤1: 在`@Tool`标注的工具方法中集成`ToolConext`参数步骤2:`ChatClient`运行时动态设置`ToolContext`参数三、填坑一、引言 在使用AI大模型的工具调用机制时,工具参数都是由大模型解析用户输入上下文获取的,由大模型提供参数给本地…

本地部署MindSearch(开源 AI 搜索引擎框架),然后上传到 hugging face的Spaces——L2G6

部署MindSearch到 hugging face Spaces上——L2G6 任务1 在 官方的MindSearch页面 复制Spaces应用到自己的Spaces下&#xff0c;Space 名称中需要包含 MindSearch 关键词&#xff0c;请在必要的步骤以及成功的对话测试结果当中 实现过程如下&#xff1a; 2.1 MindSearch 简…

MyBatis Plus扩展功能

一、代码生成器 二、逻辑删除 三、枚举处理器 像状态字段我们一般会定义一个枚举&#xff0c;做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型&#xff0c;对应的PO也是Integer。因此业务操作时必须手动把枚举与Integer转换&#xff0c;非常麻烦。 …

深度学习之自然语言处理CBOW预测及模型的保存

自然语言处理CBOW预测及模型的保存 目录 自然语言处理CBOW预测及模型的保存1 自然语言处理1.1 概念1.2 词向量1.2.1 one-hot编码1.2.2 词嵌入1.2.3 常见的词嵌入模型 2 CBOW预测模型搭建2.1 数据及模型确定2.1.1 数据2.1.2 CBOW模型2.1.3 词嵌入降维 2.2 数据预处理2.3 模型搭建…

qt项目配置部署

Test项目: 子项目testFileHelper 1.新建一个test项目的子项目:取名testFileHelper 2.编写测试用例 3.pro文件中引入qosbrowser 4.引入测试对象的cpp和头文件 2.在项目中引入资源文件testfile.txt,在其中输入abc 实现thrid目录复用 移动thrid 将thrild目录统一放在章…

java方法学习

java 方法 在Java中&#xff0c;方法是类&#xff08;或对象&#xff09;的行为或功能的实现。&#xff08;一起实现一个功能&#xff09;java的方法类似于其他语言的函数&#xff0c;是一段用来完成特定功能的代码片段。 方法是解决一类问题步骤的有序结合。 方法包含于类或…

基于vue和微信小程序的校园自助打印系统(springboot论文源码调试讲解)

第3章 系统设计 3.1系统功能结构设计 本系统的结构分为管理员和用户、店长。本系统的功能结构图如下图3.1所示&#xff1a; 图3.1系统功能结构图 3.2数据库设计 本系统为小程序类的预约平台&#xff0c;所以对信息的安全和稳定要求非常高。为了解决本问题&#xff0c;采用前端…