C++ --- 信号处理

news/2024/11/6 16:07:46/

目录

一.什么是信号处理

二.常见信号:

 三.signal() 函数的使用:

2.signal()注意事项:

3.使用场景:

四.raise()函数的使用:

注意事项

五.自定义信号处理函数:

代码说明:


一.什么是信号处理

在 C++ 中,信号处理是处理异步事件的一种机制。信号可以由操作系统或进程自身生成,常用于通知程序某些事件的发生,例如用户中断、程序错误等。了解信号处理可以帮助开发者编写更健壮和响应快速的程序。

C++ 提供了 signal()raise() 函数来支持简单的信号处理机制。这种机制允许程序响应系统事件,比如错误(如除零)或用户中断(如按下 Ctrl+C)。通过 signal()raise(),我们可以自定义如何在特定信号被触发时执行自定义操作。

二.常见信号:

  • 信号(Signal):信号是操作系统向进程发送的异步通知,用于表示某个事件的发生。每种信号都有一个唯一的编号。
  • 信号的用途
    • 通知进程终止、挂起或继续运行。
    • 捕获错误或异常情况。
    • 处理用户输入(如中断)。

信号名称

信号编号

描述

SIGHUP

1

终端挂断(Hangup)

SIGINT

2

中断信号(通常通过按下 Ctrl+C 触发)

SIGQUIT

3

退出(Quit)

SIGILL

4

非法指令(Illegal Instruction)

SIGABRT

6

程序异常终止信号

SIGFPE

8

程序异常终止信号

SIGKILL

9

强制终止(Kill)

SIGSEGV

11

无效内存访问信号(如访问非法地址)

SIGPIPE

13

管道破裂(Broken Pipe)

SIGALRM

14

定时器到期(Alarm Clock)

SIGTERM

15

终止请求信号

SIGUSR1

10

用户定义信号 1

SIGUSR2

12

用户定义信号 2

 三.signal() 函数的使用:

1.signal()函数如何使用? 

 signal() 函数用于设置信号处理函数,以指定在特定信号到达时执行的操作。

#include <csignal>// 定义函数签名
void (*signal(int signum, void (*handler)(int)))(int);
  • 参数
    • signum:要捕获的信号编号(例如 SIGINTSIGABRT 等)。
    • handler信号处理函数的地址,表示在信号发生时需要执行的操作。可以是自定义的处理函数,或标准处理动作 SIG_DFL(默认动作)和 SIG_IGN(忽略信号)。
  • 返回值:返回先前的信号处理函数指针,或 SIG_ERR 表示错误。
#include <iostream>
#include <csignal>
#include <cstdlib>
using namespace std;// 自定义信号处理函数
void signalHandler(int signum) {cout << "收到信号 " << signum << ",程序即将终止。\n";// 清理并关闭// 终止程序  exit(signum);
}int main() {// 设置 SIGINT(Ctrl + C 中断)的信号处理函数signal(SIGINT, signalHandler);// 设置 SIGTERM(程序终止请求)的信号处理函数signal(SIGTERM, signalHandler);cout << "按 Ctrl+C 以发送 SIGINT 信号,或等待程序发出 SIGTERM 信号。\n";// 无限循环,保持程序运行while (1) {cout << "程序正在运行...\n";sleep(1); // 模拟程序工作,延迟1秒}return 0;
}

代码解析:

  • 信号处理函数 signalHandler:接受信号编号 signum 作为参数。打印信号编号并终止程序。
  • 设置信号处理:通过 signal(SIGINT, signalHandler);signal(SIGTERM, signalHandler);,我们将 signalHandler 函数设置为 SIGINTSIGTERM 信号的处理函数。
  • 程序运行:程序进入无限循环,每秒输出一次状态信息,直到接收到 SIGINTSIGTERM 信号。

2.signal()注意事项:

  • 信号处理函数的限制信号处理函数应尽可能简单,因为它会中断程序的正常执行。应避免在信号处理函数中调用诸如 mallocfreeprintf 等非线程安全的函数。
  • 跨平台性:虽然 signal() 在不同平台上可用,但信号的行为可能不同。例如,有些信号在 Windows 上可能不支持。
  • 信号默认行为:使用 SIG_DFL 恢复信号的默认处理行为,使用 SIG_IGN 忽略信号。

3.使用场景:

  1. 资源清理:当程序被外部信号中断时,可以用信号处理函数进行资源清理操作,例如关闭文件或释放内存。
  2. 控制程序流程:在长时间运行的程序中,可以通过捕获特定信号来控制程序的行为,比如暂停、重启或终止。
  3. 错误处理:捕获 SIGFPESIGSEGV 等信号可以在发生严重错误时执行特定操作,而不是让程序崩溃。

四.raise()函数的使用:

在C++中,raise() 函数是一个用来发送信号的标准库函数,定义在 <csignal> 头文件中。它的主要用途是向调用进程发送特定的信号,这可以用来控制程序的行为,比如终止程序、暂停程序等。

#include <csignal>int raise(int signum);
  • 参数signum:要发送的信号编号。
  • 返回值:成功发送信号返回 0,如果信号无法被发送,返回非零值。
#include <iostream>
#include <csignal>
#include <cstdlib>
#include <unistd.h>
using namespace std;// 信号处理函数
void signalHandler(int signum) {cout << "Caught signal: " << signum << endl;// 退出程序exit(signum);
}int main() {// 注册信号处理函数signal(SIGINT, signalHandler);signal(SIGTERM, signalHandler);cout << "Process ID: " << getpid() << endl;cout << "Press Ctrl+C to send SIGINT signal." << endl;// 无限循环,等待信号while (true) {sleep(1); // 暂停一秒}return 0;
}

注意事项

  • 使用 raise() 发送信号时,通常不会产生立即的影响,因为信号的处理是异步的。信号处理程序会在程序的当前执行上下文中被调用。
  • 在多线程程序中,信号会影响整个进程,而不是单个线程。

raise() 函数在调试和程序控制中非常有用,可以用来模拟信号的发送,帮助开发者更好地理解信号的处理。

五.自定义信号处理函数:

自定义信号处理函数可以用来记录日志、重启程序等高级功能。以下是另一个示例代码,处理除零错误(SIGFPE)和无效内存访问(SIGSEGV)信号。

#include <iostream>
#include <csignal>
#include <cstdlib>void signalHandler(int signum) {if (signum == SIGFPE) {std::cerr << "收到 SIGFPE(除零错误),请检查计算逻辑。\n";} else if (signum == SIGSEGV) {std::cerr << "收到 SIGSEGV(无效内存访问),请检查指针。\n";} else {std::cerr << "收到未知信号,编号:" << signum << "\n";}exit(signum); // 终止程序
}int main() {// 注册 SIGFPE 和 SIGSEGV 信号signal(SIGFPE, signalHandler);signal(SIGSEGV, signalHandler);std::cout << "除零错误测试:5 / 0\n";int result = 5 / 0; // 触发 SIGFPEreturn 0;
}
代码说明:
  1. 捕获 SIGFPE 和 SIGSEGV 信号:注册 SIGFPESIGSEGV,通过 signalHandler 处理除零错误和无效内存访问。
  2. 触发信号:当 5 / 0 执行时,产生 SIGFPE,程序进入 signalHandler

http://www.ppmy.cn/news/1544852.html

相关文章

[MySQL]系统函数

聚合函数 聚合函数是纵向计算的函数&#xff0c;一般在SELECT语句中使用 函数描述COUNT()统计指定列不为NULL的记录行数MAX()计算指定列的最大值&#xff0c;字符串类型列使用字符串排序运算MIN()计算指定列的最小值&#xff0c;字符串类型列使用字符串排序运算SUM()计算指定列…

防重方案-订单防重方案笔记

订单防重设计 订单重复提交概念解决方案前端防重机制后端防重机制利用Token机制基于数据库的唯一索引 Token机制方案介绍 其他 订单重复提交概念 重复提交指&#xff0c;连点按钮进行重复提交操作&#xff0c;不包括刷新后的重新下单&#xff0c;重新下单已非同一订单的概念。…

DolphinScheduler资源中心

DolphinScheduler资源中心 1 简介 资源中心通常用于上传文件、UDF 函数和任务组管理。 standalone 环境可选择本地文件目录作为上传文件夹&#xff08;无需Hadoop部署&#xff09; 也可选择上传到 Hadoop 或 MinIO 集群。此时需要有 Hadoop&#xff08;2.6&#xff09;或 MinIO…

React.js教程:从JSX到Redux的全面解析

文章目录 一、介绍二、react脚手架三、jsx语法和react组件jsx的基本语法jsx的行内样式jsx的类名classNameif条件渲染map循环渲染创建组件方法 四、可视区渲染 (React- virtualized)五、React-redux 一、介绍 javascript库&#xff0c;起源于Facebook的内部项目&#xff0c;类似…

【那些年踩过的坑-前端篇- Mac版本】Mac电脑如何升级node.js

Mac电脑如何升级node.js 一 、mac可以用node.js的多版本管理器n来升级和切换二、使用Homebrew 一 、mac可以用node.js的多版本管理器n来升级和切换 mac可以用node.js的多版本管理器n来升级和切换&#xff0c;命令如下&#xff1a; sudo npm cache clean -f //清除node.js的ca…

andrular输入框input监听值传递

效果图&#xff1a; step1: E:\projectgood\ajnine\untitled4\src\app\apple\apple.component.html <button mat-button (click)“openDialog()”>Open dialog step2: E:\projectgood\ajnine\untitled4\src\app\apple\apple.component.ts import {Component, inject}…

Perl 环境安装

Perl 环境安装 Perl 是一种广泛使用的高级、通用、解释型、动态编程语言。它最初由 Larry Wall 在 1987 年设计,现在由 Perl 5 和 Perl 6 两个主要版本组成。Perl 适合于多种编程任务,包括系统管理、Web 开发、网络编程、游戏开发等。在开始使用 Perl 进行编程之前,您需要在…

如何更新已经发布的 NPM 组件库

要更新已经发布的 NPM 组件库&#xff0c;可以按照以下步骤操作&#xff1a; 更新版本号&#xff1a; 每次发布新的版本&#xff0c;都需要更新 package.json 中的 version 字段。NPM 使用 语义化版本 规则&#xff0c;即格式为 major.minor.patch&#xff0c;例如 1.0.1。版本…