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系统编程之高级信号处理
概述 在前一篇文章中,我们介绍了signal函数、sigaction函数等基本的信号处理方法。在本篇中,我们将介绍信号处理的一些高级用法,包括:阻塞与解除阻塞、定时器等。 阻塞与解除阻塞 有时候,我们不希望某个信号立即被处理…...
深度学习驱动的车牌识别:技术演进与未来挑战
一、引言 1.1 研究背景 在当今社会,智能交通系统的发展日益重要,而车牌识别作为其关键组成部分,发挥着至关重要的作用。车牌识别技术广泛应用于交通管理、停车场管理、安防监控等领域。在交通管理中,它可以用于车辆识别、交通违…...
钉钉快捷免登录 通过浏览器打开第三方系统,
一、钉钉内跳转至浏览器的实现 使用钉钉JSAPI的跳转接口 在钉钉内通过dd.biz.navigation.openLink方法强制在系统浏览器中打开链接。此方法需在钉钉开发者后台配置应用权限,确保应用具备调用该API的资格37。 示例代码: dd.ready(() > {dd.biz.navigat…...

力扣——杨辉三角
题目链接: 链接 题目描述: 思路: 直接找规律,按照数学的思路来 每一行的列最大索引 < 行索引 实现代码: 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 录入新曲子过程 三 展示,与链接视频地址1 主要功能函数一览2 下载链接3 视频效果 一 基本介绍 …...
mysql之规则优化器RBO
文章目录 MySQL 基于规则的优化 (RBO):RBO 的核心思想:模式匹配与规则应用RBO 的主要优化规则查询重写 (Query Rewrite) / 查询转换 (Query Transformation)子查询优化 (Subquery Optimization) - RBO 的重中之重非相关子查询 (Non-Correlated Subquery)…...

MySQL数据库——表的约束
1.空属性(null/not null) 两个值:null(默认的)和not null(不为空) 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法…...
vue2.x 中子组件向父组件传递数据主要通过 $emit 方法触发自定义事件方式实现
在 Vue 2.x 中,子组件向父组件传递数据主要通过 自定义事件 的方式实现。具体步骤如下: 1. 子组件通过 $emit 触发事件 子组件可以使用 $emit 方法触发一个自定义事件,并将数据作为参数传递给父组件。 语法: this.$emit(事件名…...

洛谷 P1102 A-B 数对(详解)c++
题目链接:P1102 A-B 数对 - 洛谷 1.题目分析 2.算法原理 解法一:暴力 - 两层for循环 因为这道题需要你在数组中找出来两个数,让这两个数的差等于定值C就可以了,一层for循环枚举A第二层for循环枚举B,求一下看是否等于…...
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 的主窗口是平台窗口,默认是可见的,这会影响视觉效果。那么怎么隐藏 ImGui 的主窗口呢? 这很简单,但是需要针对后端做一些修改。 本文仅介绍在 glfwopengl3 和 win32dx11 两种实现上如何修改。 在 win32dx11 实现上&#…...
ubuntu磁盘清理垃圾文件
大头文件排查 #先查看是否是内存满了,USER 很高即是满了 du -f#抓大头思想,优先删除大文件#查看文件目录 内存占用量并排序,不断文件递归下去 du --max-depth1 -h /home/ -h | sort du --max-depth1 -h /home/big/ -h | sort 缓存文件清理…...

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

大语言模型微调的公开JSON数据
大语言模型微调的公开JSON数据 以下是一些可用于大语言模型微调的公开JSON数据及地址: EmoLLM数据集 介绍:EmoLLM是一系列能够支持理解用户、帮助用户心理健康辅导链路的心理健康大模型,其开源了数据集、微调方法、训练方法及脚本等。数据集按用处分为general和role-play两种…...
C++STL容器之set
1.介绍 set容器是C标准模板库(STL)中的一个关联容器,用于存储唯一的元素。set中的元素是自动排序的,不允许重复。set通常基于红黑树(一种自平衡二叉查找树)实现,因此插入、删除和查找操作的时间…...

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

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...