「C++系列」信号处理

人工智能教程】,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。

点击跳转到网站:【人工智能教程

一、信号处理

在C++中,信号处理是一个重要的功能,用于处理操作系统发送的各种信号。这些信号可以是由用户产生的(如Ctrl+C产生的SIGINT信号),也可以是由操作系统产生的(如除零错误产生的SIGFPE信号)。处理信号可以帮助程序更优雅地处理异常情况,而不是直接崩溃。

以下是如何在C++中进行信号处理的步骤和一些示例代码:

1. 包含必要的头文件

首先,你需要包含处理信号所需的头文件:

#include <csignal>
#include <iostream>

2. 定义信号处理函数

信号处理函数是一个具有特定签名的函数,它接受一个整型参数(表示信号编号),并且没有返回值(即返回类型为void)。

void signalHandler(int signum) {
    
    
    std::cout << "Interrupt signal (" << signum << ") received.\n";
    // 清理并关闭
    // ...
    exit(signum);
}

3. 注册信号处理函数

使用std::signal函数将信号与你的处理函数关联起来。

int main() {
    
    
    // 注册信号处理函数
    signal(SIGINT, signalHandler);

    while (true) {
    
    
        std::cout << "Waiting for signal...\n";
        sleep(1); // 模拟一些工作
    }

    return 0;
}

4. 编译和运行

编译并运行你的程序。当程序运行时,你可以通过发送一个SIGINT信号(例如,通过Ctrl+C)来触发信号处理函数。

g++ -o signal_example signal_example.cpp
./signal_example

注意事项

  1. 信号处理函数的限制

    • 信号处理函数应该尽量简单,不应该调用非异步信号安全的函数(如mallocprintf等,这些函数可能不是线程安全的)。
    • 信号处理函数不应该抛出异常。
  2. 使用sigaction代替signal

    • signal函数在某些系统上可能有不可预测的行为,而sigaction提供了更强大和更可靠的功能。
    • sigaction允许你指定更多的信号处理选项,并且可以处理更复杂的信号掩码。

以下是一个使用sigaction的示例:

#include <csignal>
#include <iostream>
#include <cstring> // For memset

void signalHandler(int signum) {
    
    
    std::cout << "Interrupt signal (" << signum << ") received.\n";
    exit(signum);
}

int main() {
    
    
    struct sigaction sigIntHandler;

    sigIntHandler.sa_handler = signalHandler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;

    sigaction(SIGINT, &sigIntHandler, NULL);

    while (true) {
    
    
        std::cout << "Waiting for signal...\n";
        sleep(1);
    }

    return 0;
}

二、可以捕捉的信号

在C++中,可以捕捉的信号种类依赖于操作系统和具体的C运行时库实现。不过,POSIX标准定义了一套通用的信号,这些信号在大多数类Unix系统(如Linux和macOS)上都是可用的。以下是一些常见的可以捕捉的信号及其用途:

  • SIGINT (中断信号):通常由用户输入Ctrl+C产生,用于中断程序的执行。
  • SIGTERM (终止信号):请求程序终止运行,可以被捕捉和处理。
  • SIGKILL (杀死信号):强制终止程序,不能被捕捉或忽略。
  • SIGHUP (挂起信号):当终端会话结束时发送,用于通知程序其控制终端已经关闭。
  • SIGQUIT (退出信号):通常由用户输入Ctrl+\产生,产生核心转储文件并终止程序。
  • SIGABRT (异常终止信号):由abort函数产生,用于异常终止程序。
  • SIGFPE (浮点异常信号):当发生浮点运算错误(如除以零)时发送。
  • SIGSEGV (段错误信号):当程序试图访问未分配的内存时发送。
  • SIGPIPE (管道破裂信号):当向没有读端的管道写数据时发送。
  • SIGALRM (闹钟信号):由alarm函数设置的定时器到期时发送。

以下是一个使用sigaction来捕捉SIGINT信号的C++代码案例:

#include <iostream>
#include <csignal>
#include <cstring> // For memset
#include <unistd.h> // For sleep

// 信号处理函数
void signalHandler(int signum) {
    
    
    std::cout << "Caught signal " << signum << std::endl;
    // 执行一些清理工作...
    // 然后退出程序
    exit(signum);
}

int main() {
    
    
    // 设置sigaction结构体
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signalHandler; // 设置信号处理函数
    // 清空信号集,并添加要阻塞的信号(在这个例子中不需要阻塞任何信号)
    sigemptyset(&sa.sa_mask);
    // 设置sigaction标志(在这个例子中不需要特殊标志)
    sa.sa_flags = 0;

    // 注册信号处理函数
    if (sigaction(SIGINT, &sa, nullptr) == -1) {
    
    
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    // 模拟程序正在运行
    while (true) {
    
    
        std::cout << "Program is running. Press Ctrl+C to interrupt." << std::endl;
        sleep(1); // 休眠1秒
    }

    return 0; // 注意:由于有无限循环,这行代码实际上不会被执行
}

在这个例子中,我们创建了一个名为signalHandler的信号处理函数,它会在捕捉到SIGINT信号时被调用。然后,我们使用sigaction函数将SIGINT信号与signalHandler函数关联起来。程序进入一个无限循环,每秒打印一条消息,直到用户按下Ctrl+C来发送SIGINT信号并触发信号处理函数。

请注意,不是所有的信号都可以被捕捉或忽略。例如,SIGKILLSIGSTOP信号就不能被捕捉或忽略。此外,即使某些信号可以被捕捉,但处理它们时也需要特别小心,因为信号处理函数的执行环境可能受到限制(例如,不能使用某些标准库函数)。
在这里插入图片描述

三、相关链接

  1. Visual Studio Code下载地址
  2. Sublime Text下载地址
  3. 「C++系列」C++简介、应用领域
  4. 「C++系列」C++ 基本语法
  5. 「C++系列」C++ 数据类型
  6. 「C++系列」C++ 变量类型
  7. 「C++系列」C++ 变量作用域
  8. 「C++系列」C++ 常量知识点-细致讲解
  9. 「C++系列」C++ 修饰符类型
  10. 「C++系列」一篇文章说透【存储类】
  11. 「C++系列」一篇文章讲透【运算符】
  12. 「C++系列」循环
  13. 「C++系列」判断
  14. 「C++系列」函数/内置函数
  15. 「C++系列」数字/随机数
  16. 「C++系列」数组
  17. 「C++系列」字符串
  18. 「C++系列」指针
  19. 「C++系列」引用
  20. 「C++系列」日期/时间
  21. 「C++系列」输入/输出
  22. 「C++系列」数据结构
  23. 「C++系列」vector 容器
  24. 「C++系列」类/对象
  25. 「C++系列」继承
  26. 「C++系列」重载运算符/重载函数
  27. 「C++系列」多态
  28. 「C++系列」数据抽象
  29. 「C++系列」数据封装
  30. 「C++系列」 接口(抽象类)
  31. 「C++系列」文件和流
  32. 「C++系列」异常处理
  33. 「C++系列」动态内存
  34. 「C++系列」命名空间
  35. 「C++系列」模板
  36. 「C++系列」预处理器

猜你喜欢

转载自blog.csdn.net/xuaner8786/article/details/143117885