C++学习---信号处理机制、中断、异步环境

文章目录

  • 前言
  • 信号处理
    • signal()函数
      • 关于异步环境
    • 信号处理函数示例
    • raise()函数

前言


信号处理

关于信号,信号是一种进程间通信的机制,用于在程序执行过程中通知进程发生了一些事件。在Unix和类Unix系统中,信号是一种异步通知机制,通过发送信号,一个进程可以通知另一个进程发生了某个事件,如按下 Ctrl+C、除零错误等。

在C++中,可以使用 头文件提供的信号处理机制来捕获和处理信号。

信号的基本概念:

  • 信号编号:每个信号都有一个唯一的编号,用来标识不同的事件。例如,SIGINT 是表示中断的信号。
  • 信号处理器: 信号处理器是一个函数,用于处理接收到的信号。你可以为每种信号指定一个处理函数。

常见的信号

  • SIGINT:中断信号,通常由用户按下 Ctrl+C 生成。
  • SIGSEGV:段错误信号,表示非法内存访问。
  • SIGTERM:终止信号,表示进程被要求终止。
  • SIGKILL:强制终止信号,表示进程被强制终止。

signal()函数

C++使用 signal 函数可以为特定的信号注册信号处理函数

语法使用:

void (*signal(int signum, void (*handler)(int)))(int);

也可以写成:

signal(SIGINT, signalHandler);

在上述代码中,

  • signum(SIGINT):要注册的信号的编号。
  • handler(signalHandler):要注册的信号处理函数的指针。

信号处理函数的声明:

void handlerFunction(int signum)

关于信号处理函数的定义应该尽量简单,因为它在异步环境中执行,同时有一些函数(例如‘printf’,‘malloc’)不是异步安全的,所以尽量不要在信号处理函数中使用它们。

关于异步环境

异步环境是指程序执行时存在多个同时运行的线程或进程,这些线程或进程在执行过程中可能会相互干扰,因为它们共享某些资源(如内存、文件描述符等)。在异步环境中,执行顺序是不确定的,因此程序的行为可能受到非常复杂的影响。

printfmalloc 不是异步安全的主要是因为它们在执行时可能涉及到对共享资源的访问,而这样的访问在异步环境中是不安全的。

  1. printf:
    • print函数通常会使用标准输出(stdout),而在异步环境中,多个线程或进程可能会同时尝试写入标准输出,导致输出内容混乱。
    • 在标准库中的输出函数(如 printf)通常使用全局锁(mutex)来保护对输出流的访问,但这并不能解决所有的异步安全问题。在信号处理函数中使用 printf 可能导致死锁或其他竞态条件。
  2. malloc:
    • malloc 函数用于动态分配内存,而在异步环境中,多个线程或进程可能同时尝试分配或释放内存,这可能导致内存管理错误。

因此,在异步环境中,为了确保代码的正确性,应该尽量避免在信号处理函数或多线程环境中使用不可重入(non-reentrant)的函数。不可重入函数是指在执行过程中依赖于全局状态静态变量的函数,而这在异步环境中可能导致不确定的结果。

为了在异步环境中安全使用输出函数和内存分配函数,通常建议使用异步安全的替代版本。例如,在信号处理函数中,可以使用 write 函数代替 printf,而在多线程环境中,可以使用 pthread 库提供的线程安全的输出函数和内存分配函数。


信号处理函数示例

#include <iostream>
#include <csignal>// 信号处理函数
void signalHandler(int signum) {std::cout << "Received signal: " << signum << std::endl;// 自定义处理逻辑可以在这里添加// ...// 恢复对 SIGINT 的默认处理signal(SIGINT, SIG_DFL);
}int main() {// 注册信号处理函数signal(SIGINT, signalHandler);std::cout << "Press Ctrl+C to trigger the signal." << std::endl;// 一个简单的循环,使程序保持运行while (true) {// 等待信号的到来}return 0;
}

在上述代码中,声明了一个自定义的信号处理函数signalHandler;之后的main函数中,用signal注册信号处理函数,来处理SIGINT信号。signal函数的第一个参数就是要识别的信号的编号,第二个参数就是指向信号处理函数的指针。

而在信号处理函数signalHandler中,可以添加自定义的处理逻辑。

上述代码运行后,因为while(ture),程序会一直保持运行,直到我们按下Ctrl+C发生中断后,signal函数在捕获信号后,信号处理函数发挥作用,打印了Received signal: 2;

因为SIGINT 的信号编号是 2,所以signum的值是2;

如果想要在信号处理完成后恢复对该信号的默认处理,可以使用 signal(SIGINT, SIG_DFL)。

忽略和恢复信号:

  • 使用 signal(SIGINT, SIG_IGN) 可以忽略 SIGINT 信号。
  • 使用 signal(SIGINT, SIG_DFL) 可以恢复对 SIGINT 的默认处理。

关于恢复信号,当你按下 Ctrl+C 触发 SIGINT 信号时,如果没有 signal(SIGINT, SIG_DFL); 这一行,那么程序将继续执行 signalHandler 函数,但不会将 SIGINT 的处理方式恢复为默认。这意味着如果再次按下 Ctrl+C,signalHandler 函数将再次被调用,而不会终止程序。

实际上,如果不将 SIGINT 恢复为默认处理方式,程序可能会对多次 Ctrl+C 信号作出相应,而不是默认的行为(终止程序)。


raise()函数

raise 函数是用于在程序中手动触发一个信号的函数。

声明:

int raise(int sig);
  • sig:要触发的信号的编号。

raise 函数返回一个整数值,表示函数调用的结果。如果成功发送信号,返回 0;如果失败,返回非零值。

示例:

#include <csignal>
#include <iostream>// 信号处理函数
void signalHandler(int signum) {std::cout << "Received signal: " << signum << std::endl;
}int main() {// 注册信号处理函数signal(SIGINT, signalHandler);std::cout << "Press Ctrl+C to trigger the signal." << std::endl;// 模拟其他程序逻辑int count = 0;while (true) {// 模拟其他程序逻辑std::cout << "Working... (" << count << ")" << std::endl;// 在某个条件下手动触发 SIGINT 信号if (count > 500) {std::cout << "Manually triggering SIGINT..." << std::endl;raise(SIGINT);}// 模拟其他程序逻辑// ...// 增加计数count++;}return 0;
}

上述代码的运行结果:

在这里插入图片描述

可以看到在进行俩次的模拟生成信号后,程序就停止了,这是因为没有重新注册 SIGINT 的处理函数,程序将使用默认的信号处理方式,即终止程序。

如果想要第一次信号处理后继续运行,可以重新注册 SIGINT 的处理函数。
在signalHandler函数中添加:

// 重新注册信号处理函数signal(SIGINT, signalHandler);

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

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

相关文章

Kibana使用Watcher监控服务日志并发送飞书报警(Markdown)

Watcher是什么 Kibana Watcher 是 Elasticsearch 的监控和告警工具&#xff0c;它允许你设置和管理告警规则以监控 Elasticsearch 数据和集群的状态。Kibana Watcher 可以监测各种指标和数据&#xff0c;然后在满足特定条件时触发警报。它提供了一种强大的方式来实时监控 Elas…

​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型

内容来源&#xff1a;xiaohuggg Distil-Whisper&#xff1a;比Whisper快6倍&#xff0c;体积小50%的语音识别模型 ​该模型是由Hugging Face团队开发&#xff0c;它在Whisper核心功能的基础上进行了优化和简化&#xff0c;体积缩小了50%。速度提高了6倍。并且在分布外评估集上…

【Qt之QWizard】使用1

QWizard使用 描述方法枚举&#xff1a;enum QWizard::WizardButton枚举&#xff1a;enum QWizard::WizardOption枚举&#xff1a;enum QWizard::WizardStyle枚举&#xff1a;enum QWizard::WizardPixmap常用成员方法槽函数信号 示例设置标题添加page页设置按钮文本设置自定义按…

Windows配置IP-SAN(iSCSI)

之前写了《Linux配置IP-SAN&#xff08;iSCSI&#xff09;》&#xff0c;现在简单记录Windows配置IP-SAN&#xff08;iSCSI&#xff09;&#xff0c;基本过程都是一样的。一些原理请参考《Linux配置IP-SAN&#xff08;iSCSI&#xff09;》&#xff0c;更详细一些。 目录 一、确…

Windows conan环境搭建

Windows conan环境搭建 1 安装conan1.1 安装依赖软件1.1.1 python安装1.1.2 git bash安装1.1.3 安装Visual Studio Community 20191.1.3.1 选择安装的组件1.1.3.2 选择要支持的工具以及对应的SDK 1.1.4 vscode安装 1.3 验证conan功能1.4 查看conancenter是否包含poco包1.5 查看…

面试官问 Spring AOP 中两种代理模式的区别?很多面试者被问懵了

面试官问 Spring AOP 中两种代理模式的区别?很多初学者栽了跟头&#xff0c;快来一起学习吧&#xff01; 代理模式是一种结构性设计模式。为对象提供一个替身&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标对象&#xff0c;并允许在将请求提交给对象前后进行一…

服务器中了locked勒索病毒怎么处理,locked勒索病毒解密,数据恢复

近几年&#xff0c;网络应用技术得到了迅速发展&#xff0c;越来越多的企业开始走向数字化办公&#xff0c;极大地为企业的生产运营提供了帮助&#xff0c;但是网络技术的发展也为网络安全埋下隐患。最近&#xff0c;locked勒索病毒非常嚣张&#xff0c;几乎是每隔两个月就会对…

媒体软文投放的流程与媒体平台的选择

海内外媒体软文&#xff1a;助力信息传播与品牌建设 在当今数字化时代&#xff0c;企业如何在庞大的信息海洋中脱颖而出&#xff0c;成为品牌建设的领军者&#xff1f;媒体软文投放无疑是一项强大的策略&#xff0c;通过选择合适的平台&#xff0c;精准投放&#xff0c;可以实…

动手学深度学习——序列模型

序列模型 1. 统计工具1.1 自回归模型1.2 马尔可夫模型 2. 训练3. 预测4. 小结 序列模型是一类机器学习模型&#xff0c;用于处理具有时序关系的数据。这些模型被广泛应用于自然语言处理、音频处理、时间序列分析等领域。 以下是几种常见的序列模型&#xff1a; 隐马尔可夫模型…

探索数据湖和大数据在亚马逊云服务云存储服务上的威力

文章作者&#xff1a;Libai 引言 在当今数字化的环境中&#xff0c;组织生成的数据量正以前所未有的速度增长。数据量的激增催生了对高效存储和管理解决方案的需求。数据湖和亚马逊云服务云存储服务上的大数据是一个强大的组合&#xff0c;使组织能够充分发挥其数据的潜力。 亚…

【ubuntu 快速熟悉】

ubuntu 快速熟悉 2.ubuntu桌面管理器3.ubuntu常见文件夹说明4.ubuntu任务管理器4.1 gnome桌面的任务管理器4.2 实时监控GPU4.3 top 命令 5.ubuntu必备命令5.1 .deb文件5.2 查找命令5.2.1 find文件搜索5.2.2 which查找可执行文件的路径5.2.3 which的进阶&#xff0c;whereis5.2.…

人工智能与充电技术:携手共创智能充电新时代

人工智能与充电技术&#xff1a;携手共创智能充电新时代 摘要&#xff1a;本文探讨了人工智能与充电技术的结合及其在未来充电设施领域的应用。通过分析智能充电系统的技术原理、优势以及挑战&#xff0c;本文展望了由人工智能驱动的充电技术为未来电动交通带来的巨大变革与机…

网易有道上线“易魔声” 开源语音合成引擎 用户可免费下载使用

网易有道上线“易魔声” 开源语音合成引擎 用户可免费下载使用 刚刚&#xff0c;我们上线了「易魔声」开源语音合成&#xff08;TTS&#xff09;引擎&#xff01;&#x1f389;&#x1f389;&#x1f389; 「易魔声」&#xff0c;是一款有道自研TTS引擎&#xff0c;目前支持中…

【NI-DAQmx入门】多通道数据采集

1.通道扩展解释 通道扩展是扩展数据采集设备的通道以包含另一个设备的通道的过程&#xff0c;从而有效地创建具有更多通道的任务。当使用通道扩展时&#xff0c;DAQmx 自动在 DAQmx 驱动程序级别路由触发器和时钟&#xff0c;以便多个设备同步。为了使设备作为一个整体运行&…

笔试题之指针和数组的精讲

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

论文笔记:AttnMove: History Enhanced Trajectory Recovery via AttentionalNetwork

AAAI 2021 1 intro 1.1 背景 将用户稀疏的轨迹数据恢复至细粒度的轨迹数据是十分重要的恢复稀疏轨迹数据至细粒度轨迹数据是非常困难的 已观察到的用户位置数据十分稀疏&#xff0c;使得未观察到的用户位置存在较多的不确定性真实数据中存在大量噪声&#xff0c;如何有效的挖…

63基于matlab的生物地理的优化器(BBO)被用作多层感知器(MLP)的训练器。

基于matlab的生物地理的优化器&#xff08;BBO&#xff09;被用作多层感知器&#xff08;MLP&#xff09;的训练器。粒子群优化&#xff08;PSO&#xff09;、蚁群优化&#xff08;ACO&#xff09;、遗传算法&#xff08;GA&#xff09;、进化策略&#xff08;ES&#xff09;和…

Prim算法(C++)

目录 介绍&#xff1a; 代码&#xff1a; 结果&#xff1a; 介绍&#xff1a; Prim算法是一种用于解决最小生成树问题的贪心算法。该算法的主要思想是从一个顶点开始&#xff0c;不断向图中添加边&#xff0c;直到构成一棵包含所有顶点的生成树&#xff0c;使得树的边权之…

Rust编程中的线程间通信

1.消息传递 为了实现消息传递并发&#xff0c;Rust 标准库提供了一个 信道&#xff08;channel&#xff09;实现。信道是一个通用编程概念&#xff0c;表示数据从一个线程发送到另一个线程。 可以将编程中的信道想象为一个水流的渠道&#xff0c;比如河流或小溪。如果你将诸如…

VS项目属性变量

VS项目属性变量 $(SolutionDir) 获取解决方案的路径 $(Platform) 平台名字 → x86 / x64 $(ProjectName) 工程名字 $(Configuration) 当前的项目模式 → Debug / Release