当前位置: 首页 > news >正文

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

概述

        在前一篇文章中,我们介绍了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;
}

相关文章:

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

概述 在前一篇文章中&#xff0c;我们介绍了signal函数、sigaction函数等基本的信号处理方法。在本篇中&#xff0c;我们将介绍信号处理的一些高级用法&#xff0c;包括&#xff1a;阻塞与解除阻塞、定时器等。 阻塞与解除阻塞 有时候&#xff0c;我们不希望某个信号立即被处理…...

深度学习驱动的车牌识别:技术演进与未来挑战

一、引言 1.1 研究背景 在当今社会&#xff0c;智能交通系统的发展日益重要&#xff0c;而车牌识别作为其关键组成部分&#xff0c;发挥着至关重要的作用。车牌识别技术广泛应用于交通管理、停车场管理、安防监控等领域。在交通管理中&#xff0c;它可以用于车辆识别、交通违…...

钉钉快捷免登录 通过浏览器打开第三方系统,

一、钉钉内跳转至浏览器的实现 使用钉钉JSAPI的跳转接口 在钉钉内通过dd.biz.navigation.openLink方法强制在系统浏览器中打开链接。此方法需在钉钉开发者后台配置应用权限&#xff0c;确保应用具备调用该API的资格37。 示例代码&#xff1a; dd.ready(() > {dd.biz.navigat…...

力扣——杨辉三角

题目链接&#xff1a; 链接 题目描述&#xff1a; 思路&#xff1a; 直接找规律&#xff0c;按照数学的思路来 每一行的列最大索引 < 行索引 实现代码&#xff1a; class Solution {public List<List<Integer>> generate(int numRows) {List<List<In…...

stm32108键C-B全调性_动态可视化乐谱钢琴

108键全调性钢琴 一 基本介绍1 项目简介2 实现方式3 项目构成 二 实现过程0 前置基本外设驱动1 声音控制2 乐谱录入&基础乐理3 点阵屏谱点动态刷新4 项目交互控制5 录入新曲子过程 三 展示&#xff0c;与链接视频地址1 主要功能函数一览2 下载链接3 视频效果 一 基本介绍 …...

mysql之规则优化器RBO

文章目录 MySQL 基于规则的优化 (RBO)&#xff1a;RBO 的核心思想&#xff1a;模式匹配与规则应用RBO 的主要优化规则查询重写 (Query Rewrite) / 查询转换 (Query Transformation)子查询优化 (Subquery Optimization) - RBO 的重中之重非相关子查询 (Non-Correlated Subquery)…...

MySQL数据库——表的约束

1.空属性&#xff08;null/not null&#xff09; 两个值&#xff1a;null&#xff08;默认的&#xff09;和not null&#xff08;不为空&#xff09; 数据库默认字段基本都是字段为空&#xff0c;但是实际开发时&#xff0c;尽可能保证字段不为空&#xff0c;因为数据为空没办法…...

vue2.x 中子组件向父组件传递数据主要通过 $emit 方法触发自定义事件方式实现

在 Vue 2.x 中&#xff0c;子组件向父组件传递数据主要通过 自定义事件 的方式实现。具体步骤如下&#xff1a; 1. 子组件通过 $emit 触发事件 子组件可以使用 $emit 方法触发一个自定义事件&#xff0c;并将数据作为参数传递给父组件。 语法&#xff1a; this.$emit(事件名…...

洛谷 P1102 A-B 数对(详解)c++

题目链接&#xff1a;P1102 A-B 数对 - 洛谷 1.题目分析 2.算法原理 解法一&#xff1a;暴力 - 两层for循环 因为这道题需要你在数组中找出来两个数&#xff0c;让这两个数的差等于定值C就可以了&#xff0c;一层for循环枚举A第二层for循环枚举B&#xff0c;求一下看是否等于…...

python用 PythonNet 从 Python 调用 WPF 类库 UI 用XAML

pythonnet 是pythonhe.net通用的神器不多介绍了. 这次这基本上跟python没有关系了. 和winform一样先导包 import clr clr.AddReference("PresentationFramework.Classic, Version3.0.0.0, Cultureneutral, PublicKeyToken31bf3856ad364e35") clr.AddReference(&…...

C++——list模拟实现

目录 前言 一、list的结构 二、默认成员函数 构造函数 析构函数 clear 拷贝构造 赋值重载 swap 三、容量相关 empty size 四、数据访问 front/back 五、普通迭代器 begin/end 六、const迭代器 begin/end 七、插入数据 insert push_back push_front 八、…...

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-utils.py

utils.py ultralytics\data\utils.py 目录 utils.py 1.所需的库和模块 2.def img2label_paths(img_paths): 3.def get_hash(paths): 4.def exif_size(img: Image.Image): 5.def verify_image(args): 6.def verify_image_label(args): 7.def visualize_image_ann…...

Linux 内核 RDMA CM 模块分析:drivers/infiniband/core/cma.c

一、引言 随着高性能计算和大数据处理需求的不断增长,远程直接内存访问(RDMA)技术在数据中心和高性能计算领域得到了广泛应用。RDMA 允许数据直接在不同系统的内存之间传输,而无需经过 CPU 和操作系统的干预,从而显著提高了数据传输效率和系统性能。Linux 内核中的 RDMA …...

Flask flash() 消息示例

目录 安装 Flask 入门:Flask flash() 基本示例 进阶:使用 Flask-WTF Flash 登录结果消息 详解:get_flashed_messages() 详解:flash() 消息的完整生命周期 Flask 提供 flash() 用于向 用户传递临时消息,通常用于: • 表单提交成功或失败 • 用户登录、注册、退出提…...

ImGui 学习笔记(三)—— 隐藏主窗口窗口关闭检测

ImGui 的主窗口是平台窗口&#xff0c;默认是可见的&#xff0c;这会影响视觉效果。那么怎么隐藏 ImGui 的主窗口呢&#xff1f; 这很简单&#xff0c;但是需要针对后端做一些修改。 本文仅介绍在 glfwopengl3 和 win32dx11 两种实现上如何修改。 在 win32dx11 实现上&#…...

ubuntu磁盘清理垃圾文件

大头文件排查 #先查看是否是内存满了&#xff0c;USER 很高即是满了 du -f#抓大头思想&#xff0c;优先删除大文件#查看文件目录 内存占用量并排序&#xff0c;不断文件递归下去 du --max-depth1 -h /home/ -h | sort du --max-depth1 -h /home/big/ -h | sort 缓存文件清理…...

vue-fastapi-admin 部署心得

vue-fastapi-admin 部署心得 这两天需要搭建一个后台管理系统&#xff0c;找来找去 vue-fastapi-admin 这个开源后台管理框架刚好和我的技术栈所契合。于是就浅浅的研究了一下。 主要是记录如何基于原项目提供的Dockerfile进行调整&#xff0c;那项目文件放在容器外部&#xf…...

大语言模型微调的公开JSON数据

大语言模型微调的公开JSON数据 以下是一些可用于大语言模型微调的公开JSON数据及地址: EmoLLM数据集 介绍:EmoLLM是一系列能够支持理解用户、帮助用户心理健康辅导链路的心理健康大模型,其开源了数据集、微调方法、训练方法及脚本等。数据集按用处分为general和role-play两种…...

C++STL容器之set

1.介绍 set容器是C标准模板库&#xff08;STL&#xff09;中的一个关联容器&#xff0c;用于存储唯一的元素。set中的元素是自动排序的&#xff0c;不允许重复。set通常基于红黑树&#xff08;一种自平衡二叉查找树&#xff09;实现&#xff0c;因此插入、删除和查找操作的时间…...

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

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

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...