【Linux操作系统】Linux系统编程中信号捕捉的实现

在Linux系统编程中,信号是一种重要的机制,用于实现进程间通信和控制。当某个事件发生时,如用户按下Ctrl+C键,操作系统会向进程发送一个信号,进程可以捕获并相应地处理该信号。本篇博客将介绍信号的分类、捕获与处理方式,以及信号的默认操作。希望通过本篇博客,你能够更好地理解Linux系统编程中信号的概念与应用。

文章目录

    • [1. 什么是信号?](#1. 什么是信号? "#1__7")
    • [2. 信号的分类](#2. 信号的分类 "#2__14")
    • [3. 信号的处理方式](#3. 信号的处理方式 "#3__23")
    • [4. 信号的捕获与处理](#4. 信号的捕获与处理 "#4__34")
      • [4.1 `signal`](#4.1 signal "#41_signal_35")
      • [4.2 `sigaction`](#4.2 sigaction "#42_sigaction_83")
    • [5. 信号的默认操作](#5. 信号的默认操作 "#5__139")
    • 总结

1. 什么是信号?

在Linux系统中,信号是一种用于进程间通信和控制的机制。当某个事件发生时,内核会向进程发送一个信号,进程可以选择捕获并处理这个信号,或者使用默认的处理方式。

信号可以由多种事件触发,例如用户按下Ctrl+C键、进程发生错误、子进程退出等。每个信号都有一个唯一的编号,以及一个预定义的默认行为。


2. 信号的分类

  1. 标准信号(Standard Signals) :这些信号的编号在1到31之间,是POSIX标准中定义的。例如,SIGINT信号(编号为2)是由用户按下Ctrl+C键触发的,SIGTERM信号(编号为15)是用于终止进程的信号。
  2. 实时信号(Real-time Signals) :这些信号的编号在32到63之间,也是POSIX标准中定义的。实时信号提供了更高的优先级和更精确的触发时间。
  3. 自定义信号(User-defined Signals) :这些信号可以由用户自定义,其编号大于64。

3. 信号的处理方式

  1. 忽略(Ignore) :进程可以选择忽略某个特定的信号,这样当该信号发生时,进程不会做任何处理。但是,某些信号是不能被忽略的,例如SIGKILL和SIGSTOP。
  2. 捕获(Catch) :进程可以通过注册信号处理函数来捕获某个信号。当信号发生时,内核会调用注册的信号处理函数来处理该信号。
  3. 执行默认操作(Default Action) :每个信号都有一个预定义的默认行为,例如终止进程、终止进程并生成核心转储文件等。

4. 信号的捕获与处理

4.1 signal

作用signal函数用于捕获和处理信号。

原型

c 复制代码
#include <signal.h>

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

参数

  • signum:要捕获的信号编号。
  • handler:信号处理函数的指针。

返回值 :返回之前对该信号的处理函数的指针。如果出错,则返回SIG_ERR

示例 :下面是一个示例,演示如何使用signal函数来捕获和处理SIGINT信号(用户按下Ctrl+C键)。

c 复制代码
#include <stdio.h>
#include <signal.h>

void sigint_handler(int signum) {
    printf("Received SIGINT signal\n");
}

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

    printf("Press Ctrl+C to send SIGINT signal\n");

    while (1) {
        // 无限循环,等待信号的发生
    }

    return 0;
}

示例解释

  • 在上面的示例中,我们定义了一个名为sigint_handler的信号处理函数。当接收到SIGINT信号时,该函数会被调用,并打印一条消息。
  • main函数中,我们使用signal函数来注册sigint_handler函数作为SIGINT信号的处理函数。这样,当用户按下Ctrl+C键时,操作系统会发送SIGINT信号给进程,并调用sigint_handler函数来处理该信号。
  • main函数的无限循环中,我们等待信号的发生。这样,进程会一直运行,直到接收到SIGINT信号或其他终止信号为止。
  • 当我们按下Ctrl+C键时,会触发SIGINT信号,进程会调用sigint_handler函数,并打印一条消息。

4.2 sigaction

作用sigaction函数是另一种捕获和处理信号的方法,相比于signal函数,它提供了更多的灵活性和可靠性。

原型

c 复制代码
#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数

  • signum:要捕获的信号编号。
  • act:一个指向struct sigaction结构的指针,用于指定新的信号处理方式。
  • oldact:一个指向struct sigaction结构的指针,用于保存之前的信号处理方式。

返回值:若成功,返回0;若出错,返回-1。

示例 :下面是一个示例,演示如何使用sigaction函数来捕获和处理SIGINT信号(用户按下Ctrl+C键)。

c 复制代码
#include <stdio.h>
#include <signal.h>

void sigint_handler(int signum) {
    printf("Received SIGINT signal\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = sigint_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册SIGINT信号的处理函数
    sigaction(SIGINT, &sa, NULL);

    printf("Press Ctrl+C to send SIGINT signal\n");

    while (1) {
        // 无限循环,等待信号的发生
    }

    return 0;
}

示例解释

  • 在上面的示例中,我们定义了一个名为sigint_handler的信号处理函数。当接收到SIGINT信号时,该函数会被调用,并打印一条消息。
  • 我们创建了一个struct sigaction结构sa,并将sigint_handler函数指定为信号处理函数。
  • 使用sigemptyset函数初始化了sa.sa_mask,表示在处理SIGINT信号时不需要阻塞其他信号。
  • sa.sa_flags设置为0,表示不需要特殊的标志。
  • 使用sigaction函数将sa结构注册为SIGINT信号的处理方式。
  • main函数的无限循环中,我们等待信号的发生。这样,进程会一直运行,直到接收到SIGINT信号或其他终止信号为止。
  • 当我们按下Ctrl+C键时,会触发SIGINT信号,进程会调用sigint_handler函数,并打印一条消息。

5. 信号的默认操作

如果不捕获某个信号或者捕获的信号处理函数返回,进程会执行该信号的默认操作。

例如,当接收到SIGTERM信号时,进程会默认终止。下面是一个示例,演示了SIGTERM信号的默认操作:

c 复制代码
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sigterm_handler(int signum) {
    printf("Received SIGTERM signal\n");
}

int main() {
    // 注册SIGTERM信号的处理函数
    signal(SIGTERM, sigterm_handler);

    printf("Press Ctrl+C to send SIGTERM signal\n");

    while (1) {
        // 无限循环,等待信号的发生
    }

    return 0;
}

在上面的示例中,我们捕获了SIGTERM信号并注册了sigterm_handler函数作为处理函数。当接收到SIGTERM信号时,该函数会被调用,并打印一条消息。


总结

信号是Linux系统中用于进程间通信和控制的机制。我们可以通过捕获信号并注册处理函数来实现对信号的处理。在处理信号时,我们可以选择忽略、捕获或执行默认操作。

相关推荐
jjyangyou9 小时前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
憧憬一下1 天前
Pinctrl子系统中Pincontroller和client驱动程序的编写
arm开发·嵌入式·c/c++·linux驱动开发
蓝天居士1 天前
ES8388 —— 带耳机放大器的低功耗立体声音频编解码器(4)
嵌入式·音频·es8388
田三番1 天前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
启明智显1 天前
AI笔筒操作说明及应用场景
人工智能·嵌入式硬件·嵌入式·ai大模型·启明智显·esp32-s3
FreakStudio2 天前
全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现
python·单片机·嵌入式·面向对象·电子diy
Projectsauron5 天前
【STM32】通过 DWT 实现毫秒级延时
stm32·嵌入式·dwt
云中双月6 天前
如何使用Ida Pro和Core Dump文件定位崩溃位置(Linux下无调试符号的进程专享)
linux·嵌入式·gdb·调试·gcc·崩溃·ida pro·ulimit·core dump·cross compile
L_Z_J_I7 天前
超子物联网HAL库笔记:准备篇
笔记·物联网·嵌入式
飞凌嵌入式7 天前
FET113i-S核心板已支持RISC-V,打造国产化降本的更优解 -飞凌嵌入式
嵌入式硬件·嵌入式·risc-v·飞凌嵌入式