当前位置: 首页 > news >正文

技术演进中的开发沉思-83 Linux系列: 信号

今天我们再梳理一下信号的知识。有木有遇到这样的情况:程序正在读取 U 盘数据,可用户突然拔了 U 盘,程序瞬间卡死。因为代码没处理 “硬件断开” 的提醒 —— 而这个提醒,就是 Linux 里的 “信号”。

一、信号的作用

若把 Linux 系统里的每个进程比作一个独立的工位,进程间要传递紧急消息(比如 “你要被关闭了”“硬件出错了”),总不能靠 “喊”—— 信号,就是它们之间的 “即时传讯”。

早年团队里的开发、测试、运维各司其职,但遇到紧急情况(比如线上服务突然卡顿),我得立刻通知运维查日志,再让开发暂停新功能上线。信号的作用也类似:当用户按下Ctrl+C终止程序,就是 shell 进程给目标程序发了SIGINT信号;当硬件出错(比如内存读写错误),内核会给出问题的进程发SIGSEGV信号。这些信号不需要进程主动 “监听”,就像办公室里的紧急广播,一旦发出,相关进程就得停下手里的活,处理这个消息。

我还记得做移动互联网项目时,服务器进程偶尔会因内存泄漏 “僵住”,这时我们会用kill命令发SIGTERM信号,让进程优雅退出 —— 这比直接强制关闭更安全,就像提前跟同事说 “准备收尾”,而不是突然拔掉他的电脑电源。

二、信号的产生与传递

信号的产生与传递,像极了公司里发紧急通知的过程,可细分成 “谁发”“怎么传”“谁收” 三步。

1、 信号的产生:消息的 “源头”

信号不会凭空出现,总得有个 “发起者”。就像公司通知要么来自老板,要么来自行政,Linux 里的信号来源也分三类:

  • 用户操作:比如按下Ctrl+Z暂停程序(发SIGTSTP信号),这是用户给进程发消息;
  • 硬件事件:比如硬盘读写错误(发SIGIO信号)、CPU 执行错误指令(发SIGILL信号),这是硬件通过内核给进程 “报警”;
  • 进程间通信:比如进程 A 用kill()函数给进程 B 发SIGKILL信号,这是进程之间的 “主动沟通”。

我早年调试程序时,曾误把SIGKILL当成普通信号用,结果进程直接被 “秒杀”,连日志都没来得及写 —— 后来才知道,这个信号是内核直接 “下令”,进程连拒绝的机会都没有,就像老板亲自下达的 “立即执行” 指令,没有商量余地。

2、信号的传递

信号产生后,不会立刻被进程接收,而是先存到 “信号队列” 里,就像通知先放在行政部的待发箱,等进程 “有空” 了再处理。这个过程有个关键特点:进程在执行普通代码时(用户态),没法处理信号,只有当它切换到内核态(比如调用系统调用、发生中断)时,才会 “检查邮箱”,看看有没有未处理的信号。

这像极了我做部门经理时的工作节奏:平时忙着写方案、开会议(用户态),只有当我停下来查邮件、接电话(内核态)时,才会看到行政发来的紧急通知。如果进程一直处于用户态(比如死循环),信号就会一直存着,直到进程 “有空” 检查 —— 这也是为什么有些卡死的程序,按Ctrl+C没用,得用kill -9(发SIGKILL)强制终止,因为SIGKILL会跳过信号队列,直接让内核终止进程。

三、信号处理的系统调用

进程收到信号后,不能瞎处理 —— 是忽略?是执行默认操作?还是自定义处理逻辑?这就需要signal()和sigaction()这两个 “规则制定工具”。它们的区别,像极了团队里的 “简易通知” 和 “正式流程”。

1. signal ()

signal()就像同事间的口头约定:“下次我发‘咖啡好了’的消息,你就过来拿。” 它的用法简单,只需指定 “信号类型” 和 “处理函数”,适合简单场景。比如早年写命令行工具时,我用signal(SIGINT, handle_exit),让程序收到Ctrl+C时,先保存数据再退出,而不是直接崩溃。

但它有个缺点:不够稳定。不同系统对signal()的实现有差异,比如有些系统会在处理完信号后,恢复默认行为 —— 就像口头约定没写进合同,下次对方可能忘了。我创业时,曾因跨服务器部署,signal()的行为不一致导致 bug,后来才换成更可靠的sigaction()。

2. sigaction ()

如果说signal()是口头约定,sigaction()就是签了字的正式协议。它不仅能指定处理函数,还能设置 “信号掩码”(处理当前信号时,屏蔽其他信号)、“重启标志”(系统调用被信号打断后,是否自动重启)等细节。

比如做微服务开发时,我们需要进程优雅关闭:收到SIGTERM信号时,先停止接收新请求,处理完现有请求,再释放资源。这时用sigaction()就能精准控制 —— 设置信号掩码,避免处理过程中被其他信号打断;设置重启标志,确保网络调用被打断后能继续。这就像项目交接时,把每个步骤、注意事项都写进文档,避免遗漏。

最后小结:

回头看 “信号” 这一章,其实它就是 Linux 系统的 “应急沟通语言”:作用是传递紧急消息,产生与传递像公司发通知,系统调用则是约定沟通规则。从桌面开发时处理Ctrl+C,到移动互联网时优雅关闭服务,再到微服务时精准控制进程行为,我发现信号的核心逻辑从未变过 —— 它是保障系统稳定运行的 “隐形纽带”。或许技术会迭代,如信号一样 “沟通” 的本质始终如一。

http://www.xdnf.cn/news/1384381.html

相关文章:

  • 把 AI 塞进「智能门锁」——基于指纹和语音双模态的零样本离线门禁系统
  • Spring Boot中MyBatis Provider注解实现动态SQL
  • 云手机中的多开功能具体是指什么?
  • DVWA靶场通关笔记-暴力破解(Impossible级别)
  • Android 14 PMS源码分析
  • 临床研究三千问——如何将临床问题转换成科学问题(7)
  • 【网络安全领域】边界安全是什么?目前的发展及应用场景
  • Nessus 是一款免费功能强大的漏洞扫描工具,广泛用于网络安全评估。
  • eslasticsearch+ik分词器+kibana
  • 【MySQL】练习12-2:配置复制
  • 国产数据库转型指南:DBA技能重构与职业发展
  • Unity RectTransform容易混淆的基础问题
  • 3471. 找出最大的几近缺失整数
  • MyBatis延迟加载
  • LaunchScreen是啥?AppDelegate是啥?SceneDelegate是啥?ContentView又是啥?Main.storyboard是啥?
  • DoIP路由激活报文
  • 玄机靶场 | 第九章-blueteam 的小心思3
  • day083-Filebeat数据采集案例与Kibana可视化应用
  • 创建uniApp小程序项目vue3+ts+uniapp
  • Docker 核心技术:Union File System
  • ros2与gazebo harmonic机械臂仿真项目Moveit2YoloObb的优化
  • 有限与无限的游戏 之感
  • Rust 登堂 之 类型转换(三)
  • CnSTD+CnOCR的联合使用
  • 虚拟机逃逸攻防演练技术文章大纲
  • 编写TreeMap自定义排序的插曲
  • InstructGPT:使用人类反馈训练语言模型以遵循指令
  • 文本处理与模型对比:BERT, Prompt, Regex, TF-IDF
  • 在angular20中使用monaco-editor
  • 任天堂NDS中文游戏ROM精选毕业整合包整理分享! +NDS模拟器