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

Linux进程信号详解(二):信号产生

当前阶段:

一、通过终端按键产生信号

1.1 基本操作

  • Ctrl+C → SIGINT
  • Ctrl+\ →SIGQUIT 可以发送终止信号
  • Ctrl + Z -> SIGSTP 可以发送停止信号,将当前前台进程挂起到后台

设置所有信号都可以自定义捕捉 :

1.2 理解OS如何得知键盘有数据

1.3 初步理解信号起源

  • 信号其实是从纯软件角度,模拟硬件中断的行为
  • 只不过硬件中断是发给CPU,而信号是发送给进程
  • 两者都有相似性,但是层级不同

二、调用系统命令向进程发信号

kill命令可以给指定进程发送信号。

# 方式1:通过信号宏定义发送 kill -信号名 进程PID # 方式2:通过信号编号发送(推荐,更通用) kill -信号编号 进程PID # 示例:向PID为213784的进程发送SIGSEGV(11号)信号 kill -SIGSEGV 213784 kill -11 213784

示例:先运行一个后台死循环进程

// deadloop.cc #include <iostream> #include <unistd.h> int main() { while(true) { sleep(1); } }
g++ deadloop.cc -o deadloop ./deadloop & # 后台运行 ps aux | grep deadloop # 查看PID,假设是213784 kill -SIGSEGV 213784 # 发送段错误信号

进程会收到SIGSEGV(11号信号),默认动作是终止并产生core dump。

三、使用函数产生信号

3.1 kill() 函数

kill命令的底层实现,可向任意进程(需有对应权限)发送任意信号。

#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig);
  • 作用:给指定进程发送信号。

  • 返回值:成功返回0,失败返回-1。

Makefile

.PHONY:all all:testSig mykill testSig:testSig.cc g++ -o $@ $^ -std=c++11 mykill:mykill.cc g++ -o $@ $^ -std=c++11 .PHONY:clean clean: rm -f testSig mykill

mykill.cc

#include <iostream> #include <sys/types.h> #include <signal.h> #include <string> // ./mykill signumber pid int main(int argc, char *argv[]) { if (argc != 3) { std::cout << "./mykill signumber pid" << std::endl; return 1; } int signum = std::stoi(argv[1]); pid_t target = std::stoi(argv[2]); int n = kill(target, signum); if (n == 0) { std::cout << "send " << signum << " to " << target << " success." << std::endl; } return 0; }

testSig.cc

#include <iostream> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <unistd.h> void handlerSig(int sig) { std::cout << "获得了一个信号: " << sig << std::endl; } int main() { signal(SIGINT,handlerSig); int cnt = 0; while (true) { std::cout << "hello world, " << cnt++ << ", pid: " << getpid() << std::endl; sleep(1); } return 0; }

3.2 raise() 函数

自己给自己发信号,底层是调用kill(getpid(), sig)实现。

#include <signal.h> int raise(int sig);
  • 作用:给当前进程自己发送信号。

  • 返回值:成功0,失败非0。

9 号信号无法被自定义捕捉

把9号信号跳过去 , 查看是否还有其他信号无法被自定义捕捉

把9号和 19号 信号跳过去 ,查看是否还有其他信号无法被自定义捕捉

没有了 , 就只有 9号和 19 号无法自定义捕捉

3.3 abort() 函数

强制让进程异常终止,无论是否捕捉 SIGABRT 信号,进程最终都会终止(捕捉后会先执行自定义逻辑,再终止)。

#include <stdlib.h> void abort(void);

关键特性:无返回值,总是会成功,进程最终一定会异常终止。

四、硬件异常产生信号

4.1 除零异常 → SIGFPE

// divzero.cc #include <stdio.h> #include <signal.h> void handler(int sig) { printf("catch a sig : %d\n", sig); } int main() { // signal(SIGFPE, handler); // 取消注释可捕捉 int a = 10; a /= 0; // 除零错误 while(1); return 0; }

默认情况下,进程会收到SIGFPE(8号信号)并终止。如果捕捉了该信号,会一直打印“catch a sig : 8” —— 为什么一直打印?因为CPU的状态寄存器中除零标志位没有被清除,每次从异常处理返回后,再次执行除零指令又会触发异常,形成循环。

4.2 野指针 → SIGSEGV

// segv.cc #include <stdio.h> #include <signal.h> void handler(int sig) { printf("catch a sig : %d\n", sig); } int main() { // signal(SIGSEGV, handler); int *p = NULL; *p = 100; // 向NULL地址写入,非法内存访问 while(1); return 0; }

默认产生段错误(SIGSEGV,11号信号)。捕捉后也会一直打印,因为MMU异常状态未清除。

核心结论:C/C++中的除零、野指针等异常,在系统层面都是通过信号来通知进程的。

4.3 硬件异常与信号的对应关系

异常类型典型代码产生的信号信号值默认行为
除零错误a /= 0;SIGFPE8终止 + Core
野指针/段错误*p = 100; // p=nullptrSIGSEGV11终止 + Core
非法指令执行损坏的二进制代码SIGILL4终止 + Core
总线错误内存对齐错误SIGBUS7终止 + Core
浮点异常浮点溢出/下溢SIGFPE8终止 + Core
断点调试int 3指令SIGTRAP5终止 + Core

Core表示会产生 core dump 文件,用于调试分析。

4.4 核心问题:OS 怎么知道硬件异常了?

前置知识:信号全部都是由操作系统发送的 。

硬件层面的检测机制

关键组件:CPU 寄存器与状态

组件作用
EFLAGS 标志寄存器记录运算结果状态(溢出、零标志、符号标志等)
CR0 控制寄存器控制 CPU 操作模式,包含异常使能位
CR2 寄存器页故障时保存导致故障的线性地址
CR3 寄存器保存页目录表物理地址(MMU 使用)
IDT 中断描述符表存储异常处理程序的入口地址

4.5 操作系统如何识别"谁"犯了错?

当前进程上下文

http://www.jsqmd.com/news/593493/

相关文章:

  • Java全栈工程师的面试实战:从技术细节到业务场景
  • 基于SpringBoot+Vue的飘香水果购物网站管理系统设计与实现【Java+MySQL+MyBatis完整源码】
  • 终极宝可梦随机化指南:Universal Pokemon Randomizer ZX 完全使用教程
  • 保姆级教程:用ms-swift微调Qwen3-Embedding-0.6B,搞定文本相似度任务
  • 亲测有效:用这几款 AI 写综述类论文,文献梳理比手动快 20 倍
  • 墨者学院-----代码分析溯源
  • 彻底搞懂支持向量机(SVM):从“找条线分开红蓝球”到“核函数大法”
  • 保姆级教程:在Jetson Orin上从零搭建DJI OSDK + ROS2 Humble开发环境(避坑指南)
  • 前后端分离服装生产管理设计与实现系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • AI逆向实战:构建MCP工具链赋能Cursor自动化App动态分析
  • PADS 铜箔区域规则与技巧
  • 别再手动改Excel了!用VBA的For Each循环,5分钟搞定1000行数据批量处理
  • 跨平台电子书阅读器 | Readest最新版 安卓版+PC版全平台
  • 探寻2026酒店设备新势力:口碑厂商的创新之路,空调制冷/冰箱冰柜/餐饮设备/厨房设备/冷链设备,酒店设备生产厂家哪家好 - 品牌推荐师
  • 银河麒麟kylin.desktop-generic编译程序执行权限问题深度解析与实战解决方案
  • 实现可视化页面问题记录 - f
  • 避开带宽陷阱:用低成本示波器搞定MIPI CSI-2信号的眼图与时序分析
  • 深入理解Python的GIL锁:从原理到实战,多线程到底是神兵还是枷锁?
  • 别再只盯着DPD了:聊聊PA记忆效应那些让新手工程师头疼的‘玄学’现象
  • Nine PRO 邮箱 APP专业高级版 邮箱合集整理 一个就够了
  • 从CMOS Sensor原理到实战:深入浅出搞定工业相机中的Flicker Banding问题
  • Lua性能优化指南:让你的游戏不卡顿的关键技巧
  • Ctf组会-网络基础,一篇总览基本的网络知识
  • 告别双系统挤牙膏!手把手教你无损迁移Ubuntu到新NVMe固态(附DD命令进度监控)
  • 中大型团队必备:6款高口碑研发资源管理平台汇总
  • ncmdumpGUI:打破音乐格式壁垒的开源方案——音乐爱好者的格式自由实现指南
  • Cocos Creator 热更新地址动态化方案
  • 自学渗透测试第九天(linux shell脚本编写)
  • mmdetection实战:从零开始构建自定义数据集训练流程
  • 手写数字识别在FPGA上的暴力美学