学懂C++ (十九):高级教程——深入详解C++信号处理
目录
C++中的信号处理
1. 信号处理的本质
2. 主要信号类型
3. 核心关键点
4. 经典实例
代码分析
5. 进阶:信号屏蔽与多线程
例子:使用sigaction()
6. Windows中的信号处理
7. 比较与总结
示例:Windows控制台事件处理
总结
C++中的信号处理
C++中的信号处理主要涉及操作系统层面的信号机制,尤其是在Unix和Linux系统中。信号是一种异步事件的通知机制,允许程序在特定事件发生时进行响应。常见的用途包括处理异常情况、外部中断等。以下将深入探讨信号处理的本质、信号类型、核心关键点以及经典实例。
1. 信号处理的本质
信号处理的本质在于允许程序响应异步事件。当特定事件发生时,操作系统向进程发送信号,进程通过信号处理程序(信号处理函数)来响应这些信号。信号的用途包括:
- 处理用户请求(如Ctrl+C中断)
- 处理定时器
- 响应硬件异常
- 实现进程间通信
2. 主要信号类型
在Unix/Linux系统中,常见的信号包括:
- SIGINT:中断信号(通常由Ctrl+C触发)
- SIGTERM:终止信号(请求程序终止)
- SIGSEGV:段错误(访问无效内存)
- SIGALRM:定时器到期
3. 核心关键点
在进行信号处理时,需要掌握以下核心要点:
- 信号的注册与处理:可以使用
signal()
或sigaction()
函数来注册信号处理程序。 - 信号阻塞与解除阻塞:可以用
sigprocmask()
控制信号的阻塞,以防在特定代码段内被处理。 - 信号发送:可以使用
kill()
函数向进程发送信号。 - 并发性:信号处理是异步的,可能与程序的其他部分并发执行,因此需要注意线程安全。
4. 经典实例
以下是一个简单的信号处理示例,演示如何处理SIGINT
信号(通常由Ctrl+C触发)。
#include <iostream>
#include <csignal>
#include <unistd.h> // for sleep()// 信号处理函数
void signalHandler(int signum) {std::cout << "Caught signal " << signum << ", terminating gracefully..." << std::endl;// 这里可以做一些清理工作exit(signum); // 退出程序
}int main() {// 注册信号处理程序signal(SIGINT, signalHandler);std::cout << "Press Ctrl+C to trigger the signal handler..." << std::endl;// 程序主循环while (true) {std::cout << "Running..." << std::endl;sleep(1); // 每秒打印一次}return 0;
}
代码分析
-
注册信号处理程序:使用
signal(SIGINT, signalHandler)
注册信号处理函数。当程序接收到SIGINT
信号时,调用signalHandler
函数。 -
信号处理逻辑:在
signalHandler
中进行清理工作并输出通知,最后调用exit(signum)
退出程序。 -
主循环:程序在无限循环中持续运行,每秒打印一次“Running...”。按下Ctrl+C时,将捕获到
SIGINT
信号,调用处理程序并优雅地终止。
5. 进阶:信号屏蔽与多线程
在多线程程序中,信号处理变得更加复杂。关键要点包括:
- 信号屏蔽:使用
sigprocmask()
阻塞某些信号,以防在特定代码块内被处理。 - 专用信号线程:创建专门的线程处理信号,避免信号处理函数与其他线程并发执行的问题。
- 使用
sigaction()
:sigaction()
提供丰富的功能,允许设置信号处理的行为,如恢复默认处理和设置信号屏蔽字。
例子:使用sigaction()
#include <iostream>
#include <csignal>
#include <cstring>
#include <unistd.h>// 信号处理函数
void signalHandler(int signum, siginfo_t *info, void *context) {std::cout << "Caught signal " << signum << ", terminating gracefully..." << std::endl;// 这里可以做一些清理工作exit(signum); // 退出程序
}int main() {struct sigaction action;memset(&action, 0, sizeof(action));action.sa_sigaction = signalHandler; // 设置处理函数action.sa_flags = SA_SIGINFO; // 使用siginfo_t结构// 注册信号处理程序if (sigaction(SIGINT, &action, nullptr) == -1) {std::cerr << "Error registering signal handler" << std::endl;return 1;}std::cout << "Press Ctrl+C to trigger the signal handler..." << std::endl;// 程序主循环while (true) {std::cout << "Running..." << std::endl;sleep(1); // 每秒打印一次}return 0;
}
6. Windows中的信号处理
在Windows系统中,信号的概念与Unix/Linux系统有所不同。Windows使用以下机制处理异步事件:
- 异常处理:使用结构化异常处理(SEH)来处理运行时错误,允许捕获异常并执行处理逻辑。
- 控制台控制处理:通过
SetConsoleCtrlHandler()
函数注册控制台控制处理程序,响应如Ctrl+C等事件。
7. 比较与总结
- 信号机制:Unix/Linux提供标准的信号机制,允许程序使用信号进行异步事件处理;而Windows则通过异常处理和控制台事件机制完成类似功能。
- 跨平台性:虽然C++标准库提供了一些跨平台功能,但信号处理在不同操作系统中的实现方式和可用API不尽相同。因此,编写跨平台的信号处理代码时,需要考虑不同操作系统的特性和差异。
示例:Windows控制台事件处理
#include <windows.h>
#include <iostream>BOOL WINAPI ConsoleHandler(DWORD signal) {if (signal == CTRL_C_EVENT) {std::cout << "Caught Ctrl+C! Exiting gracefully..." << std::endl;return TRUE; // 阻止默认处理(程序退出)}return FALSE; // 让系统执行默认处理
}int main() {// 注册控制台控制处理程序SetConsoleCtrlHandler(ConsoleHandler, TRUE);std::cout << "Press Ctrl+C to trigger the handler..." << std::endl;// 程序主循环while (true) {std::cout << "Running..." << std::endl;Sleep(1000); // 每秒打印一次}return 0;
}
总结
C++中的信号处理是一个重要的机制,能够让程序对异步事件做出反应。理解信号的基本概念、如何注册处理程序、信号的阻塞与解除以及多线程环境中的处理逻辑是掌握信号处理的核心。尽管在不同操作系统下信号处理机制存在差异,了解这些差异有助于编写更加健壮和可移植的代码。
相关文章:

学懂C++ (十九):高级教程——深入详解C++信号处理
目录 C中的信号处理 1. 信号处理的本质 2. 主要信号类型 3. 核心关键点 4. 经典实例 代码分析 5. 进阶:信号屏蔽与多线程 例子:使用sigaction() 6. Windows中的信号处理 7. 比较与总结 示例:Windows控制台事件处理 总结 C中的信号…...

SOMEIP_ETS_032:echoUINT8ArrayMinSize
测试目的: 确保DUT能够正确处理最小尺寸的UINT8数组参数,并且在发送和接收过程中保持参数值和顺序不变。 描述 本测试用例旨在验证DUT在处理包含最小尺寸UINT8数组参数的SOME/IP消息时,是否能够准确地发送和接收这些参数,确保返…...

JS+CSS案例:可适应上下布局和左右布局的菜单(含二级菜单)
今天,我给大家分享一个原创的CSS菜单,整个菜单全由CSS写成,仅在切换布局时使用JS。合不合意,先看看效果图。 本例图片 接下来,我来详细给大家分享它的制作方法。 文件夹结构 因为涉及到了样式表切换,所以,你需要借鉴一下我的文件夹结构。 CSS文件夹: reset.css 用于…...

【数据结构】线性表,顺序表
一. 线性表 1. 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 2. 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 3. 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理…...

Spring之最基础的创建与Bean的存储与获取(还有Maven加载jar包报错的解决方法)
目录 创建Spring项目 如何解决Maven加载jar包报错 存储Bean和取Bean 在Java中对象也称为Bean。所以后面我提到Bean,大家要知道我说的是什么。 创建Spring项目 我的idea是2022版本的,如果大家和我一样可以参考我的。 1.创建一个Maven项目。图片上忘了…...

RabbitMQ应用问题 - 消息顺序性保证、消息积压问题
文章目录 MQ 消息顺序性保证概述原因分析解决方案基于 spring-cloud-stream 实现分区消费 消息挤压问题概述原因分析解决方案 MQ 消息顺序性保证 概述 a)消息顺序性:消费者消费的消息的顺序 和 生产者发送消息的顺序是一致的. 例如 生产者 发送消息顺序…...

linux tcp通讯demo
linux tcp通讯demo代码。通过用chatgpt生成的代码。做一个代码记录。 一、基本的通讯demo server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h>…...

在 MongoDB 中,如何配置副本集以实现读写分离?
在 MongoDB 中,配置副本集以实现读写分离主要涉及以下几个步骤: 初始化副本集: 创建副本集时,需要在所有参与节点上运行 rs.initiate() 命令。这将初始化一个新的副本集。 添加成员到副本集: 使用 rs.add() 命令将所有…...

虚拟dom-Diff算法
虚拟dom-Diff算法 vue2 diff算法在vue2中就是patch,通过新旧虚拟dom对比,找到最小变化然后进行dom操作 在页面首次渲染的时候会调用一次patch并创建新的vnode,不会进行深层次的比较,然后再组件中数据发生变化的时候,…...

01创建型设计模式——单例模式
一、单例模式简介 单例模式(Singleton Pattern)是一种创建型设计模式(GoF书中解释创建型设计模式:一种用来处理对象的创建过程的模式),单例模式是其中的一种,它确保一个类只有一个实例ÿ…...

图像分割(一)
一、概述 语义分割:是把每个像素都打上标签(这个像素点是人、树、背景等) 实例分割:不光要区别类别,还要区分类别中的每一个个体 损失函数:逐像素的交叉熵;样本均衡问题 MIOU指标:…...

C++ 新经典:设计模式 目录(先留框架,慢慢来~)
C 新经典:设计模式 C 新经典:设计模式 C 新经典:设计模式第1章 设计模式与软件开发思想、编程环境介绍第2章 模板方法模式第3章 工厂模式、原型模式、建造者模式第4章 策略模式第5章 观察者模式第6章 装饰模式第7章 单件模式第8章 外观模式第…...

go之命令行工具urfave-cli
一、urfave/cli urfave/cli 是一个声明性的、简单、快速且有趣的包,用于用 Go 构建命令行工具。 二、快速使用 2.1 引入依赖 go get github.com/urfave/cli/v2 2.2 demo package mainimport ("fmt""log""os""github.com/ur…...

四种应用层协议——MQTT、CoAP、WebSockets和HTTP——在工业物联网监控系统中的性能比较
目录 摘要(Abstract) 实验设置 实验结果 节选自《A Comparative Analysis of Application Layer Protocols within an Industrial Internet of Things Monitoring System》,作者是 Jurgen Aquilina、Peter Albert Xuereb、Emmanuel Francalanza、Jasmine Mallia …...

MySQL的脏读、不可重复读、幻读与隔离级别
脏读/不可重复读/幻读 脏读 脏读(Dirty Read)发生在一个事务读取了另一个事务尚未提交的数据。如果第二个事务失败并回滚,第一个事务读到的数据就是错误的。这意味着数据从一开始就是不稳定或者“脏”的。 举例 事务A读取了某条记录的值为X。事务B修改该记录的值…...

程序员前端开发者的AI绘画副业之路:在裁员危机中寻找新机遇
正文: 在这个充满变数的时代,作为一名前端开发者,我经历了行业的起伏,见证了裁员危机和中年失业危机的残酷。在这样的背景下,我开始了利用AI绘画作为副业的探索,不仅为了寻求经济上的稳定,更是为…...

Burp Suite的使用和文件上传漏洞靶场试验
第一步:分析如何利用漏洞,通过对代码的查阅发现,代码的逻辑是先上传后删除,意味着,我可以利用webshell.php文件在上传到删除之间的间隙,执行webshell.php的代码,给上级目录创建一个shell.php木马…...

如何在Ubuntu中安装deepin wine版的企业微信
如何在Ubuntu中安装deepin wine版的企业微信 运行如下一条命令将移植仓库添加到系统中 wget -O- https://deepin-wine.i-m.dev/setup.sh | sh自此以后,你可以像对待普通的软件包一样,使用apt-get系列命令进行各种应用安装、更新和卸载清理了。 安装企业…...

案例:Nginx + Tomcat集群(负载均衡 动静分离)
目录 案例 案例环境 案例步骤 部署Tomcat服务器 部署Nginx服务器 实现负载均衡和读写分离 日志控制 案例 案例环境 操作系统 IP 地址 角色 CentOS 192.168.10.101 Nginx服务器(调度器) CentOS 192.168.10.102 Tomcat服务器① CentOS 1…...
【密码学】密码协议的分类:②认证协议
密码协议的分类有很多种方式,这里我采取的是基于协议实现的目的来分类。可以将密码协议分成三类:认证协议、密钥建立协议、认证密钥建立协议。 一、认证协议是什么? 认证协议都在认证些什么东西呢?认证一般要认证三个东西&#x…...

异步编程(Promise详解)
目录 异步编程 回调函数 回调地狱 Promise 基本概念 Promise的特点 1.Promise是一种构造函数 2.Promise接收函数创建实例 3.Promise对象有三种状态 4.Promise状态转变不可逆 5.Promise 实例创建即执行 6.Promise可注册处理函数 7.Promise支持链式调用 Promise的静…...

DjangoORM注入分享
DjangoORM注入 简介 这篇文章中,分享一些关于django orm相关的技术积累和如果orm注入相关的安全问题讨论。 攻击效果同数据库注入 从Django-Orm开始 开发角度 Django ORM(Object-Relational Mapping)是Django框架中用于处理数…...

【HBZ分享】Redis各种类型的数据结构应用场景
String(字符串类型) 计数器: incr / decr, 比如商品库存,业务号的发号器业务数据key-value缓存, 缓存结果数据,提高网站性能,缓解DB压力分布式session会话, 集群环境下存储token鉴权信息分布式锁ÿ…...

anaconda创建并且配置pytorch(完整版)
📚博客主页:knighthood2001 ✨公众号:认知up吧 ** 🎃知识星球:【认知up吧|成长|副业】介绍** ❤️如遇文章付费,可先看看我公众号中是否发布免费文章❤️ 🙏笔者水平有限,欢迎各位大…...

高级java每日一道面试题-2024年8月10日-网络篇-你对跨域了解多少?
如果有遗漏,评论区告诉我进行补充 面试官: 你对跨域了解多少? 我回答: 跨域问题,即Cross-Origin Resource Sharing(CORS),是现代Web开发中一个非常重要的概念,涉及到浏览器的安全策略——同源策略(Same…...

AtCoder Beginner Contest 365 A~E
A.Leap Year(思维) 题意: 给你一个介于 1583 1583 1583和 2023 2023 2023之间的整数 Y Y Y。 求公历 Y Y Y年的天数。 在给定的范围内, Y Y Y年的天数如下: 如果 Y Y Y不是 4 4 4的倍数,则为 365 365 …...

多机部署, 负载均衡-LoadBalance
目录 1.负载均衡介绍 1.1问题描述 1.2什么是负载均衡 1.3负载均衡的一些实现 服务端负载均衡 客户端负载均衡 2.Spring Cloud LoadBalancer 2.1快速上手实现负载均衡 2.2负载均衡策略 自定义负载均衡策略 3.服务部署(Linux) 3.1服务构建打包…...

(回溯) LeetCode 78. 子集
原题链接 一. 题目描述 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的 子集 (幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums [1,2,3] 输出&…...

DQL数据查询语言(多表处理)—/—<7>
一、多表处理 当前有两个表,一个是学生表student,一个是分数表score student表字段名表示如下(共1000条数据): score表字段表示如下(共6000条数据): 1、求每个学生的总分 SELECT …...

力扣刷题总结
去年有段时间一直在刷题,进步神速,解决了以往刷完就忘的问题,这里总结下经验,给有需要的人参考下,核心观点就仨: 1. 打好数据结构与算法基础 2. 多刷题多练习 3. 形成自己的知识体系 下图是我梳理的知识体…...