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

Linux 进程信号(上):信号产生方式和闹钟

Linux 信号机制解析。涵盖信号本质、异步通知原理、五种产生方式及键盘中断处理。详解前台后台作业控制与 alarm 定时器应用,含实战代码示例。

www发布于 2026/3/26更新于 2026/10/2288 浏览
Linux 进程信号(上):信号产生方式和闹钟

Linux 进程信号(上):信号产生方式和闹钟

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

1.1 信号的本质

信号是一种异步通知机制。简单来说,就是事件通知,但通知的到来与当前执行流不同步。

举个例子,你点了外卖然后打游戏。外卖小哥送货上门敲门是一个通知,说明外卖到了。你和外卖小哥是不同步的——你做你的游戏,他做他的配送。这就是异步关系。如果是同步,你得等他送回来再继续打游戏。

操作系统给目标进程发送信号,进程天然能够识别。因为进程和信号都是程序员写的代码,进程相当于被'教育'过的人,已经知道怎么处理信号了。

普通信号和实时信号

用 kill -l 可以查看系统中的信号列表。常用的只有 131 号,3464 号是实时信号(带 RT)。前 31 个是普通信号,我们主要关注这些。

1.2 生活中的信号与结论

生活中有很多信号,比如红绿灯、电话铃声等。这些信号产生的几乎都是异步的。

人之所以能识别信号,是因为经过教育,知道了信号对应的处理动作。操作系统同理,进程内核程序员设计好了信号的处理逻辑。

收到信号会立即处理吗?

不会立即处理。有时候中断不了,或者正在做优先级更高的事情。既然不一定立即处理,进程就必须有临时保存信号的能力。

这就好比外卖员打电话叫拿外卖,如果你答应去取却没保存这个信息,打着打着就忘了。所以,信号不会被立即处理,进程必须有临时保存信号的能力!

信号的处理方式
  1. 默认:按系统预设行为处理(如红灯停)。
  2. 忽略:直接无视该信号(如不想拿外卖)。
  3. 自定义:编写自己的处理函数(如拿完外卖直接丢了)。

后续我们将这三种统称为信号捕捉。

1.3 信号具体化

信号编号与宏

信号是有编号的,没有 0 号信号。大写的名字(如 SIGINT)是宏定义。

头文件通常包含 <signal.h>。内核中也可以查看相关定义。131 是普通信号,3464 是实时信号。

信号的保存

进程需要特定的数据类型来保存信号。通常使用位图(bitmap),比特位的位置表示信号编号,内容表示是否收到对应信号。这个位图位于进程的 PCB(进程控制块)中。

谁有资格修改内核数据结构中的字段?只有操作系统。用户通过系统调用让操作系统向目标进程发送信号。

1.4 为什么要有信号?

Linux 需要信号,是为了提供一种异步且轻量级的进程间通信与事件通知机制。它能让操作系统立即打断进程的正常执行流,通知其发生了突发状况,如用户中断(Ctrl+C)、硬件异常、定时器到期或子进程退出。信号弥补了管道或共享内存等同步通信方式的不足,是实现进程控制、异常处理和系统紧急交互的核心基础。

1.5 如何自定义捕捉信号?

我们可以使用 signal 函数对指定信号进行自定义处理。这是一个回调函数的设定。

挑一个信号,比如 2 号信号 SIGINT(对应 Ctrl+C)。默认情况下,收到 SIGINT 会终止进程。如果我们想让它不终止,就需要自定义处理。

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

void handler( sig) {
    (, sig);
}

  {
    
    signal(SIGINT, handler);
    
    () {
        sleep();
    }
     ;
}
int
printf
"Caught signal %d\n"
int
main
()
// 注册信号处理函数
while
1
1
return
0

运行后,即使按下 Ctrl+C,进程也不会立即终止,而是执行 handler 函数。这叫做信号捕捉。

注意,有两个信号不能自定义捕捉或忽略:9 号信号(SIGKILL)和 19/20 号信号(取决于系统)。9 号信号非常重要,不能被捕捉,也不能被忽略,它是强制终止进程的唯一手段。

2. 信号的产生

让 OS 给目标进程写信号,必须经过操作系统,因为只有 OS 能修改内核数据结构。

2.1 信号产生的方式

主要有五种方式:

  1. 使用系统命令产生:如 kill 命令。
  2. 通过键盘产生信号:如 Ctrl+C。
  3. 系统调用:如 kill, raise, abort。
  4. 异常:如除零错误、段错误。
  5. 软件条件产生:如管道读写端关闭。
系统命令与系统调用

kill 命令底层调用了 kill 系统调用。第一个参数是目标进程 PID,第二个参数是信号编号。

raise 是自己给自己发信号,底层封装了 kill。

abort 用于异常终止,发送 6 号信号(SIGABRT)。虽然可以设置捕捉动作,但最终进程还是会终止,属于异常处理范畴。

异常产生信号

当进程发生异常时,OS 会将其转化为信号。

  • 段错误:访问非法内存地址,触发 11 号信号(SIGSEGV)。
  • 浮点异常:如除零错误,触发 8 号信号(SIGFPE)。尽管名字叫浮点异常,它也涵盖整数运算错误。

进程自己就会收到对应的信号,这是 OS 识别并解释为信号的结果。

2.2 键盘怎么发送信号?

键盘是基于硬件中断工作的。CPU 被动等待,外设(键盘)触发中断告诉 CPU 数据来了。

操作系统收到键盘输入后,解释快捷键(如 Ctrl+C),转换成信号发送给目标进程。这里涉及进程组和会话的概念。

进程组与会话
  • 进程组:一组相关的进程,由一个进程组 ID(PGID)标识。
  • 会话 ID(SID):一组进程组的集合,通常拥有自己的终端文件。

同一个会话中,任何时刻只允许一个进程(组)在前台。前台进程能获取键盘输入,后台进程则不能。

前台与后台进程
  • 前台进程:占用当前终端,必须等执行完毕才能输入其他命令。例如 sleep 100。
  • 后台进程:在后台运行,不占用终端。启动时在命令末尾加 &。

结论:Ctrl+C 只能用于终止前台进程!

如果进程在后台,Ctrl+C 无法杀死它。需要使用 kill -9 [pid] 强制终止。

作业控制命令包括:

  • jobs:查看后台作业列表。
  • fg:将后台作业调到前台。
  • bg:将暂停的作业放到后台继续运行。
  • Ctrl+Z:暂停当前前台进程。

2.3 alarm:设置闹钟

学习一个新的函数 alarm,以及 14 号信号 SIGALRM。默认处理动作是终止进程。

闹钟的返回值

alarm(seconds) 设置若干秒后的闹钟。如果之前已设置过闹钟,返回值是剩余时间;如果取消闹钟(设为 0),返回上一个闹钟的剩余时间。

验证一下:先设置 10 秒闹钟,再设置 0 秒,返回值为 10。这说明 alarm 是一次性的,且每个进程同一时间只有一个闹钟。

如果要实现重复闹钟,需要在信号处理函数中重新设置:

void handler(int sig) {
    printf("Alarm triggered!\n");
    alarm(2); // 重新设置 2 秒后的闹钟
}

int main() {
    signal(SIGALRM, handler);
    alarm(2); // 启动第一个闹钟
    while(1) pause();
    return 0;
}
应用场景

闹钟可用于延迟操作,如 Windows 的关机程序 shutdown -t 10。

还可以实现'看门狗'机制。B 进程作为看门狗,A 进程定期'喂狗'重置计数器。如果 A 进程卡死,B 进程检测到超时则执行关机或其他保护操作。

理解闹钟原理

闹钟是软件实现的,依赖于操作系统的时钟中断。晶振触发中断,操作系统记录中断次数来计算时间。只要关注未来超时时间最近的闹钟即可,通常使用堆结构管理。


本文内容到此结束,希望对你理解 Linux 信号有所帮助。

目录

  1. Linux 进程信号(上):信号产生方式和闹钟
  2. 1. 理解信号是什么,为什么要有?
  3. 1.1 信号的本质
  4. 普通信号和实时信号
  5. 1.2 生活中的信号与结论
  6. 收到信号会立即处理吗?
  7. 信号的处理方式
  8. 1.3 信号具体化
  9. 信号编号与宏
  10. 信号的保存
  11. 1.4 为什么要有信号?
  12. 1.5 如何自定义捕捉信号?
  13. 2. 信号的产生
  14. 2.1 信号产生的方式
  15. 系统命令与系统调用
  16. 异常产生信号
  17. 2.2 键盘怎么发送信号?
  18. 进程组与会话
  19. 前台与后台进程
  20. 2.3 alarm:设置闹钟
  21. 闹钟的返回值
  22. 应用场景
  23. 理解闹钟原理

更多推荐文章

查看全部
  • DataRoom 开源大屏设计器:基于 SpringBoot 快速构建数据可视化平台
  • AI 入门:常见术语解释与误区澄清
  • OpenClaw 集成飞书命令行配置指南
  • Python 开源 AI 模型引入与测试全流程实战
  • 马年新春 Python+Stable Diffusion 生成企业营销素材
  • 深入理解并查集:原理、优化技巧与 LeetCode 实战
  • VR + 具身智能 + 人形机器人:通往现实世界的智能接口
  • Java 核心面试知识点汇总:集合、多线程、JVM 及锁机制
  • Stable Diffusion WebUI 云服务器部署实战指南
  • SpringAI 通过 Ollama 本地部署 Deepseek 模型实现对话机器人
  • AWVS Web 安全漏洞扫描工具安装与使用指南
  • Visual C++ 运行库整合安装方案:VisualCppRedist AIO
  • 算法优选:位运算技巧实战解析
  • 运维排查问题常用工具与方法论
  • OpenEUICC Android eSIM 管理工具使用指南
  • Windows 11 下利用 llama.cpp 测试 Qwen3.5 量化模型
  • Blob 文件格式详解:前端二进制数据处理实战
  • CCF-GESP 2025 年 9 月 C++ 二级真题解析
  • VS Code Copilot 实战指南:从安装到智能编码
  • Less 预处理器实战:三种运行模式与核心语法解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • 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