跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C

Linux 进程信号(上):信号产生方式与闹钟机制

综述由AI生成Linux 信号机制提供了一种异步且轻量级的进程间通信与事件通知方式。深入探讨了信号的本质、分类及处理策略,包括默认、忽略和自定义三种模式。重点分析了信号的多种产生途径,涵盖系统命令、键盘中断、系统调用及硬件异常。同时详细讲解了进程组与会话管理对前台后台信号分发的影响,并通过 alarm 函数演示了定时器机制的实现原理及其在看门狗等场景中的应用。掌握这些内容有助于开发者更好地进行系统编程和异常处理。

魔尊发布于 2026/3/30更新于 2026/6/926 浏览
Linux 进程信号(上):信号产生方式与闹钟机制

Linux 进程信号(上):信号产生方式与闹钟机制

1. 理解信号是什么,为什么要有?

1.1 信号的本质与分类

信号(Signal)是操作系统向进程发送的通知消息。它本质上是一种异步的通信机制。所谓异步,意味着通知的到来与进程当前的执行状态不同步——就像你正在打游戏,外卖小哥敲门送饭,这个敲门声就是一个异步通知,你不需要停下来等外卖员准备好再开始游戏。

在 Linux 中,信号分为普通信号和实时信号。通过 kill -l 可以查看系统支持的信号列表。常用的主要是编号 1 到 31 的普通信号,以及 34 到 64 的实时信号(带 RT 后缀)。我们日常开发中主要关注前 31 个。

1.2 信号的处理机制

进程收到信号后,不会立即处理,而是根据预设的策略来决定行为。这就像红绿灯:红灯亮时,默认是停车;如果你选择忽略,可能继续行驶;或者自定义一个动作,比如跳舞。具体来说,信号处理有三种默认策略:

  • 默认(Default):如终止进程、忽略或 Core Dump。
  • 忽略(Ignore):明确丢弃该信号。
  • 自定义(Custom):注册信号处理函数(Signal Handler)来接管逻辑。

由于信号可能随时到达,而进程可能正忙(比如在处理高优先级任务),所以内核必须为每个进程提供临时保存信号的能力。这个能力通常体现在进程的 PCB(进程控制块)中的位图里,只有操作系统有权修改这些内核数据结构。

1.3 信号的识别与存储

信号在代码中通常用宏定义表示,如 SIGINT、SIGKILL 等,对应特定的整数编号。头文件 <signal.h> 中定义了这些常量。为了高效管理多个信号是否发生,内核使用位图(Bitmap)记录,每一位代表一个信号编号,值为 1 表示已到达,0 表示未到达。

1.4 如何自定义捕捉信号?

我们可以通过 signal() 函数来设置特定信号的处理动作。例如,将 2 号信号 SIGINT(通常由 Ctrl+C 触发)的处理方式从默认的终止改为自定义函数。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void handler(int sig) {
    printf("Caught signal %d\n", sig);
}

int main() {
    // 注册信号处理函数,当 SIGINT 发生时调用 handler
    signal(SIGINT, handler);
    
    while(1) {
        sleep(1);
    }
    return 0;
}

注意,有些信号是不能被捕捉或忽略的,比如 9 号信号 SIGKILL。这是为了防止用户误操作导致无法终止进程。另外,6 号信号 SIGABRT 虽然可以注册处理器,但最终仍会导致进程异常终止。

2. 信号的产生方式

让操作系统给目标进程写入信号,必须经过 OS 权限验证。信号的产生主要有以下几种途径:

2.1 常见产生方式

  1. 系统命令:使用 kill 命令向指定 PID 发送信号。
    kill -2 [pid]
    
  2. 键盘输入:组合键如 Ctrl+C 会触发终端驱动产生中断,OS 将其转换为信号发送给前台进程组。
  3. 系统调用:程序内部调用 kill()、raise() 或 abort() 主动发送信号。
    • raise():自己给自己发信号。
    • abort():发送 6 号信号,用于异常终止并生成 Core Dump。
  4. 硬件/软件异常:如除零错误会触发 SIGFPE,非法内存访问触发 SIGSEGV(11 号信号)。
  5. 定时器到期:如 alarm() 设置的闹钟时间到,发送 SIGALRM。

2.2 键盘输入与进程组

键盘本身是硬件,它通过中断通知 CPU 有数据输入。操作系统解释快捷键(如 Ctrl+C)后,需要知道发给谁。这就涉及到了进程组和会话的概念。

  • 进程组:一组相关进程的集合,通常由同一个 Shell 启动。
  • 会话(Session):包含一个或多个进程组,拥有独立的终端文件。
  • 前台与后台:在一个会话中,同一时刻只能有一个进程组处于前台,能接收键盘输入。后台进程无法读取终端输入,一旦尝试会被暂停。

当你按 Ctrl+C 时,OS 只会把信号发送给当前会话中的前台进程组。这就是为什么后台进程(如 sleep 100 &)不会被 Ctrl+C 杀死,除非使用 kill -9 强制终止。

2.3 Alarm:设置闹钟

alarm() 函数用于设置一个一次性定时器,超时后向进程发送 SIGALRM 信号。它的返回值很有讲究:如果之前已经设置了闹钟,新调用会返回剩余时间;如果设为 0,则取消闹钟。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

volatile int counter = 0;

void alarm_handler(int sig) {
    printf("Alarm triggered! Counter: %d\n", counter++);
    // 重新设置闹钟以实现周期性触发
    alarm(2); 
}

int main() {
    signal(SIGALRM, alarm_handler);
    alarm(2); // 启动第一个闹钟
    
    while(1) {
        pause(); // 等待信号
    }
    return 0;
}

这里有个关键点:alarm 是一次性的。如果想实现周期性效果,必须在信号处理函数中再次调用 alarm()。如果在主循环中直接调用,上一个闹钟还没响就被覆盖了,导致后续收不到信号。

2.4 应用场景:看门狗

利用 alarm 和共享内存,可以实现简单的看门狗机制。一个进程定期'喂狗'重置计数器,另一个进程监控计数器,若超时未重置则执行关机或重启操作。

// 看门狗进程示例
void watchdog_handler(int signum) {
    (*counter)--;
    if(*counter <= 0) {
        system("shutdown -h now");
        exit(0);
    }
    alarm(1); // 重置计时
}

这种机制常用于守护进程的健康检查,确保服务在长时间运行后依然存活。


信号机制是 Linux 进程间通信和异常处理的核心基础。理解其产生方式、处理流程以及与其他机制(如进程组、定时器)的配合,对于编写健壮的系统级程序至关重要。

目录

  1. Linux 进程信号(上):信号产生方式与闹钟机制
  2. 1. 理解信号是什么,为什么要有?
  3. 1.1 信号的本质与分类
  4. 1.2 信号的处理机制
  5. 1.3 信号的识别与存储
  6. 1.4 如何自定义捕捉信号?
  7. 2. 信号的产生方式
  8. 2.1 常见产生方式
  9. 2.2 键盘输入与进程组
  10. 2.3 Alarm:设置闹钟
  11. 2.4 应用场景:看门狗
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Git 安装教程:Windows 环境配置与功能详解
  • 2023 年数据分析职业发展与薪资前景分析
  • AI 大模型精通之旅:从入门到专业的系统教程
  • Git 在 Windows 上的安装与配置完整指南
  • Git 在 Windows 上的安装与配置详解
  • GitHub Copilot 完整使用指南:从安装配置到高级技巧
  • OSCP 实战笔记:获取并破解 Net-NTLMv2 哈希(下)
  • Vibe Coding 时代后端程序员开发前端的最佳实践
  • BFS 实现拓扑排序:原理与 LeetCode 实战
  • 动态规划经典模型:斐波那契数列及变体
  • RAG 进阶:多模态图片检索技术实践
  • Midjourney 官网地址与语言支持说明
  • CMake 项目中 Vcpkg、Conan 与 Spack 的 C++ 依赖管理对比
  • Spring Boot 数据仓库与 ETL 工具集成实战
  • 深度对比 vLLM、SGLang 与 llama.cpp 推理引擎选型指南
  • MATLAB Compiler SDK 中的 mwArray 核心类使用详解
  • Spring Boot 数据仓库与 ETL 工具集成实践
  • Spring Boot 数据仓库与 ETL 工具集成实战
  • AMD 显卡在 AI 绘画中的配置与优化指南
  • KrLongAI 旗博士:本地部署 AI 数字人口播视频自动化工程

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online