[linux仓库]信号产生[进程信号·贰]

[linux仓库]信号产生[进程信号·贰]


🌟 各位看官好,我是!

🌍 Linux == Linux is not Unix !


🚀 今天来学习Linux的信号产生,从多种信号产生方式反推理解之前一直未解决的疑惑。

👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享更多人哦!

目录

信号产生

信号产生方式

键盘产生

kill命令产生

函数产生信号

kill系统调用

raise

abort 

软件条件

验证IO效率问题

理解闹钟

模拟OS行为

硬件异常

理解 /0

理解野指针

如何理解键盘产生信号?

总结


信号产生

对信号的概念进行一定的理解后,就可以从时间维度上讲解信号产生的话题

信号产生方式

键盘产生

  • Ctrl+C (SIGINT) 已经验证过,这⾥不再重复
  • Ctrl+\(SIGQUIT)可以发送终⽌信号并⽣成core dump⽂件,⽤于事后调试(后⾯详谈)
  • Ctrl+Z(SIGTSTP)可以发送停⽌信号,将当前前台进程挂起到后台等。

至于键盘是如何产生信号的话题需要到后面进行揭晓.

kill命令产生

我们之前演示过用Kill命令的9号信号可以杀死进程.这里让每一个信号都有自己的捕捉方式或者忽视该信号,验证每一个信号是否都会调用自定义函数.

void handler(int signo) { std::cout <<"我这个进程:" << getpid() << ",抓到了一个信号: " << signo << std::endl; // 我没有在这个函数里终止进程哦! } int main { for(int i = 1;i <= 31; i++) signal(i, handler); //signal(i, SIG_IGN); while (true) { std::cout<<"我是一个进程:"<<getpid()<<std::endl; sleep(1); } retrun 0; }
一 一 验证后,会发现有几个信号比较特别, 9号 和 19号 信号不可被捕捉,不可被忽略 --> 为什么这样做呢? --> 防止有人设置病毒,并且将每个信号都设置成自定义捕捉方法,导致你无法杀掉该进程.

函数产生信号

kill系统调用
kill 命令实际上底层一定调用了 kill函数。 kill 函数可以给⼀个指定的进程发送指定的信号。

int kill(pid_t pid, int sig);

pid : 目标进程

sig : 什么信号

自定义实现kill命令: 

int main(int argc, char *argv[]) { if (argc != 3) { std::cout << "Usage:" << argv[0] << "signumber pid" << std::endl; return 1; } //会把命令参数切到命令行参数表里,是一个一个的字符串,因此要stoi转成数字 int signumber = std::stoi(argv[1]); pid_t target = std::stoi(argv[2]); int n = kill(target, signumber); if (n < 0) { perror("kill"); return 2; } return 0; } 

  

raise
raise 函数可以给当前进程发送指定的信号(⾃⼰给⾃⼰发信号)。

int raise(int sig);
void handler(int signal) { std::cout << "收到了一个信号:" << signal << std::endl; } int main() { signal(2,handler); while(true) { sleep(1); raise(2); } return 0; }
abort 
abort 函数使当前进程接收到指定信号⽽异常终⽌。
void abort(void);

那么abort是给当前进程发送几号信号呢?给自己发送6号新号,如何证明呢?

软件条件

SIGPIPE 是⼀种由软件条件产⽣的信号,在“管道”中已经介绍过了。坏掉的管道,就是软件不满足 --> 也是OS给目标进程发送信号!

本节主要介绍 alarm 函数 和 SIGALRM 信号。

unsigned int alarm(unsigned int seconds);调用 alarm 函数可以设定⼀个闹钟,也就是告诉内核在 seconds 秒之后给当前进程发SIGALRM 信号,该信号的默认处理动作是终止当前进程。这个信号就是14号信号(默认动作为Term).

  函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。闹钟响一次,默认终止进程
alarm调用,一次只运行一个进程,设置一个闹钟,以最新的为准第二次设置闹钟的新时间,会取消上一次的闹钟,返回上一次闹钟的剩余时间!闹钟为0则为取消闹钟

验证IO效率问题
如下图所示可见printf函数这类IO操作会降低效率

理解软件条件:

在操作系统中,信号的软件条件指的是由软件内部状态或特定软件操作触发的信号产⽣机制。这些条件包括但不限于定时器超时(如alarm函数设定的时间到达)、软件异常(如向已关闭的管道写数据产⽣的SIGPIPE信号)等。当这些软件条件满⾜时,操作系统会向相关进程发送相应的信号,以通知进程进⾏相应的处理。简而言之,软件条件是因操作系统内部或外部软件操作⽽触发的信号产⽣。
理解闹钟

系统闹钟,其实本质是OS必须自身具有定时功能,并能让⽤⼾设置这种定时功能,才可能实现闹钟这样的技术。

如果每一个进程都有一个闹钟,有上百个进程就有上百个闹钟。那么这些闹钟是否需要被OS管理?如何管理?提出来一种对闹钟进行管理的方案 -->

先描述! 再组织!    

内核中定时器数据结构:定时器超时时间expires和处理⽅法function。

struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long); unsigned long data; struct tvec_t_base_s *base; };

操作系统管理定时器,采⽤的是时间轮的做法,但是我们为了简单理解,可以把它在组织成为"堆结构"。 

模拟OS行为

通过alarm设定闹钟,使得每1s都会向该进程发送14号新号,14号信号已经设置为自定义捕捉,去执行自定义函数,理解为硬件中断.在这个自定义函数中,可以做自己想做的事情,如进程调度、进程切换等等.就如同OS每固定一段时间都会去检测时间片是否到了,是否需要进行进程切换等等...

using func_t = std::function<void()>; std::vector<func_t> cb; void FlushDisk() { std::cout << "我是一个刷盘的操作" << std::endl; } void sched() { std::cout << "我是一个进程调度" << std::endl; } void handler(int signo) { for(auto &f : cb) { f(); } (void)signo; std::cout << "我是一个信号捕捉函数, 我被调用了" << std::endl; alarm(1); } // 写一段代码,理解OS int main() { cb.push_back(FlushDisk); cb.push_back(sched); signal(SIGALRM, handler); alarm(1); while(true) { pause(); // 等待信号到来,否则暂停 } }

硬件异常

常见的异常如 /0 错误 , 野指针 --> 会导致我们的进程崩溃了.

但是我们从未想过为什么这些异常会导致进程崩溃呢?

因为软件问题,被操作系统识别,给目标进程发送了信号然后进程处理信号,默认终止了进程!

下面写两段程序,分别是 /0 错误 以及 野指针 的异常,先是验证 /0 错误 和 野指针 是向目标进程发送几号信号,再来从深层进行理解.

 

 

产生信号都是有操作系统产生的.那么是谁让OS产生的?用户,OS内部的软件条件. 
理解 /0

首先,我们的代码和数据会加载到物理地址空间,再通过页表和虚拟地址空间建立映射关系,CPU执行代码的时候,一定是在调度某一个进程! 假设此时CPU内的一个寄存器eax存放着a为10的值,ebx存放着0,此时会有 /0 错误,而CPU里有一个寄存器EFLAGS(控制盒状态寄存器),简单理解为⼀个位图,对应着⼀些状态标记位、溢出标记位,记录CPU单次运算时所对应的状态.此时当CPU执行 /0 这一行代码时,由EFLAGS检测到是非法操作,CPU触发硬件异常,那么OS需不需要知道呢?OS是软硬件资源的管理者,因此告诉OS"我出错了,快来帮我" --> OS靠 struct task_struct *current(进程描述结构体),它永远指向 “当前正在被 CPU 调度的进程” , 知道了是这个进程的代码在搞事情,就需要对这个进程进行某种操作,即发送信号.CPU内部的寄存器本质是:当前进程的硬件上下文.一旦该进程被默认杀掉了,进程的硬件上下文就不存在了,从而使CPU的报错就没有了!

因此本质是:OS是为了恢复CPU的正常运行

那为什么当我对8号信号执行自定义捕捉时,会被OS一直调度啊?

当CPU告诉OS"我报错了",OS会向目标进程发送信号,又因为8号信号有了自定义捕捉方法,并没有清理内存,关闭进程打开的⽂件,切换进程等操作,所以CPU中还保留上下⽂数据以及寄存器内容
,当执行完这自定义方法时,此时又会恢复硬件上下文,让CPU继续执行这行数据,又检测到是非法操作,依次循环下去.看起来也是在被一直调度,但这其实是异常的情况,占用着CPU的资源!!!

 

理解野指针
int *p = nullptr; *p = 10;

OS是如何识别野指针问题,并终止进程的? 

野指针 --> 硬件报错 --> OS写信号 --> 进程终止!!! 

如何理解键盘产生信号?

 

那么键盘具体是如何让OS知道键盘外设有数据了?举ctrl + c 来说:

当我们键盘上按下 ctrl + c 时,会向CPU发送硬件中断,此时CPU通过里面内置的针脚识别发出硬件中断的是键盘(实际上就是高低电频) , 告诉CPU要键盘被按下了,此时OS会去识别是普通数据还是组合键(即将数据从外设读入内存),而OS内部内置了一套中断向量表(之后会扒出源码提供),执行键盘处理方法.

总结

本文详细介绍了Linux系统中的信号产生方式及其原理。主要内容包括:

  1. 键盘组合键产生信号(如Ctrl+C、Ctrl+\、Ctrl+Z);
  2. 通过kill命令和函数产生信号,重点分析了9号和19号信号的不可捕捉特性;
  3. 软件条件产生的信号(如alarm函数和SIGALRM信号);
  4. 硬件异常产生的信号(如除零错误和野指针访问)。

文章深入探讨了信号产生的底层机制,包括CPU寄存器状态、中断处理等硬件层面原理,并解释了操作系统如何管理这些信号。最后通过代码示例展示了信号处理的实际应用场景,如模拟操作系统调度等。

Read more

保姆级教程:Windows Git 安装全流程,手把手带你从 0 到 1 (2025版)

保姆级教程:Windows Git 安装全流程,手把手带你从 0 到 1 (2025版)

Git 是程序员的必备工具。对于 Windows 用户来说,安装过程中的几十个英文选项往往让人头大。本教程将手把手带您走完安装流程,确保您的环境配置最优化、最符合现代开发标准。 第一步:下载安装包 1. 下载地址 * 官方网站:git-scm.com/download/win * 下载方式:推荐直接点击页面上的 "Click here to download" 或者 "Git for Windows/x64 Setup" 下载独立的 .exe 安装程序。 * 注:虽然可以用 Winget 命令行下载,但传统安装包更适合初次配置。 2. 版本选择 (x64 vs ARM64) * 绝大多数电脑(Intel/AMD

By Ne0inhk
论文精读(二)| 开源软件漏洞感知技术综述

论文精读(二)| 开源软件漏洞感知技术综述

笔者链接:扑克中的黑桃A 专栏链接:论文精读 本文关键词:开源软件; 漏洞感知; 软件安全 引 诸位技术同仁: 本系列将系统精读的方式,深入剖析计算机科学顶级期刊/会议论文,聚焦前沿突破的核心机理与工程实现。 通过严谨的学术剖析,解耦研究范式、技术方案及实证方法,揭示创新本质。我们重点关注理论-工程交汇点的技术跃迁,提炼可迁移的方法论锚点,助力诸位的技术实践与复杂问题攻坚,共推领域持续演进。 每日一句 明天是新的一天, 你也不再是昨天的你。 目录 引 每日一句 文献来源 一.解决的问题 二.为什么开源软件漏洞更难防? 1. 开源软件的 “双刃剑” 特性 透明性 协同开发 披露延迟 2. 漏洞生命周期中的防御窗口 三.基于代码的漏洞感知:像 “体检” 一样扫描代码 1. 机器学习:让

By Ne0inhk
GitHub Spec Kit 中文使用说明

GitHub Spec Kit 中文使用说明

📖 工具简介 GitHub Spec Kit 是GitHub开源的规范驱动开发(Specification-Driven Development, SDD)工具包,它彻底颠覆了传统软件开发模式。在传统开发中,代码是王者,规范服务于代码;而Spec Kit实现了权力反转——规范成为主导,代码服务于规范。规范不再是指导实现的文档,而是能够直接生成实现的可执行文件。 该项目在过去30天内星标数量约20k,近期平均每天新增超1k星标,这反映出其高速增长趋势和社区的积极反馈。这种受欢迎度源于其易用性和强大的功能,帮助开发者高效处理标准化工作流。 🎯 核心理念:权力反转 传统模式:规范 → 指导 → 代码实现 SDD模式:规范 → 直接生成 → 代码实现 * 规范优先:规范成为开发的首要驱动力,而非辅助文档 * 可执行规范:规范足够精确和完整,能够直接生成工作系统 * 消除鸿沟:彻底消除规范与实现之间的转译差距 * AI协同增强:通过AI的理解能力让自然语言规范变为可执行代码 * 持续进化:生产反馈直接更新规范,驱动下一轮生成 🚀 安装方法 1. 环境要求

By Ne0inhk
【开发者必备工具】Windows 11 安装 Git 完整指南

【开发者必备工具】Windows 11 安装 Git 完整指南

📝 适合人群:Git 初学者、Windows 11 用户 ⏱️ 预计时间:10-15 分钟 🎯 学习目标:成功在 Windows 11 上安装并配置 Git 📖 什么是 Git? Git 是一个分布式版本控制系统,简单来说,它可以帮助你: * ✅ 保存代码历史:记录每次代码修改,随时可以回退到之前的版本 * ✅ 团队协作:多人同时开发同一个项目而不会互相干扰 * ✅ 分支管理:创建不同的分支来尝试新功能,不影响主代码 * ✅ 代码备份:将代码推送到远程仓库(如 GitHub、Gitee),安全可靠 💡 小提示:即使你是一个人开发,Git 也能帮你更好地管理代码版本,强烈推荐使用! 🖥️ 测试环境 本文档基于以下环境进行测试,不同配置的电脑安装过程基本相同: * 💻 设备规格: * 处理器:13th Gen Intel® Core™ i5-13500H

By Ne0inhk