学懂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…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...