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

Linux操作系统之信号概念启程

前言:

在前段时间,我们开始了对于Linux操作系统中的进程间通信的章节内容,并为大家介绍了关于管道和system V共享内存的相关知识。

但是system V标准中还有信号量与消息队列两个知识点。这两个的系统调用的使用方法与共享内存差不多,因为三者同属于system V标准。所以我们就不再过多赘述,后面可以作为大家的补充知识点,感兴趣的同学可以自己去了解一下。

我们从今天开始进入信号的章节。

信号其实勉强也能算得上是进程间通信的一种,但严格意义上来说,二者区别还是蛮大的,所欲离我们这里把分开。

我们前面在进程终止那里曾经提到过进程终止的方案就有信号,但是没有深入了解。

今天这篇文章,将会为大家带来初步的关于信号的知识点,难度比较简单,大家学起来还是蛮容易的。话不多说,马上开始正文吧!

一、什么是信号

在我们生活中无处不存在着信号:

古代的狼烟烽火,现在马路上随处可见的红绿灯,甚至于你每天上早八定的闹钟,都是一种信号

信号有一个特点,就是异步

什么是异步性

就是突发的,不可预料。我们用官方的点语言来说就是:信号可能在任何时刻到达,打断进程的正常执行流。

你说闹钟和红绿灯我们可以预料,怎么会有异步性呢?

那如果你的手机没电了!如果交通拥堵有交警专门去手动控制交通!

这种情况的出现我们无法预料,所以,闹钟与红绿灯也是一种信号。

敌人多久来?我们多久点燃烽火?你的一个电话什么时候打过来,都是突发的,我们把这个称为信号的异步性。

二、信号的处理阶段

在linux系统中,你怎么能识别信号呢?

:识别信号是内置的,进程识别信号,是内核程序员写的内置特性。

信号产生之后,你知道怎么处理吗?
:知道。
如果信号没有产生,你知道怎么处理信号吗?
:知道。
所以,信号的处理⽅法,在信号产生之前,我们就已经准备好了。

处理信号,是需要⽴即处理吗?我可能正在做优先级更⾼的事情,
:不会⽴即处理。
那么什么时候处理信号呢??
:合适的时候。

所以,信号的处理可分为三个阶段:

  1. 信号产生:由硬件、软件或用户触发。

  2. 信号保存:内核暂存信号,等待进程处理。

  3. 信号处理:进程执行注册的处理函数。

1. 信号产生方式

类型示例信号触发条件
硬件异常SIGSEGV非法内存访问(段错误)
终端控制SIGINT (Ctrl+C)用户中断进程
系统调用SIGKILL (kill -9)强制终止进程
定时器SIGALRMalarm() 或 setitimer() 触发
进程间通信SIGUSR1用户自定义信号

即:1、终端按键(键盘)。2、系统命令。3、函数。4、软件条件。5、硬件异常 

2. 信号保存

信号保存是Linux信号处理机制中至关重要的一个环节,它确保了信号在产生后能够被正确地暂存和管理,直到进程准备好处理它们。

内核通过进程PCB中的信号位图记录未决信号(我们后面会讲到,本文只是给大家提概念,不带你挖坑):

  • 如果信号被阻塞(屏蔽),则暂存为未决状态

  • 解除阻塞后,信号才会递送给进程。

3. 信号处理

进程对信号的处理方式有三种:

  1. 默认行为(如 SIGINT 终止进程)。

  2. 忽略信号(如 SIGCHLD 避免僵尸进程)。

  3. 自定义处理:通过 signal() 或 sigaction() 注册处理函数。

三、举个样例认识信号

我们平时在启动一个进程时,我们想要提前让它结束,我们会输入什么呢?

#include <iostream>
#include <unistd.h>int main()
{while (true){std::cout << "I am a process, I am waiting signal!" << std::endl;sleep(1);}return 0;
}

 

可以看见,我们在bash的前台启动一个进程,当我们用键盘按下ctrl + C时,会产⼀个硬件中断,随后被OS获取,于是被解释成信号,发送给⽬标前台进程。前台进程因为收到信号,进而引起进程退出。

其实,ctrl + C的本质是向前台进程发送 SIGINT 2 号信号。

我们可以证明一下,但这里要引入一个系统调用:signal

我们前文说过,处理信号有三种,默认方式,忽略,和自定义。

而signal就是实现自定义的一种调用。signum参数是我们要捕获的信号编号:如SIHINT,SIGTERM,handler是一个信号处理函数的指针,这个函数一般由我们自己设置,或者是一个特殊值:SIG_IGN(忽略信号),SIG_DEL(默认行为) 

所以我们可以这些写:

#include <iostream>
#include <unistd.h>
#include<signal.h>void handler(int signumber)
{std::cout<<"捕获到信号2,开始执行自定义处理方法"<<std::endl;
}int main()
{signal(2,handler);while(true){std::cout<<"I am a process, I am waiting signal!"<<std::endl;sleep(1);}return 0;
}

这里有一点要注意,为了符合参数类型一致,必须得在我们的handler加一个参数 int signumber,哪怕你的代码中不会用到这个参数。

 通过以上这个代码,我们就把对二号信号的捕捉后的处理方法,变成了我们自己定义的方法。

可以看见,我们现在从键盘输入strl c就不会杀死进程了。我们只能手动给该进程kill发送信号杀死。

Shell可以同时运⾏⼀个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产⽣的信号。
如果我们要执行一个后台进程,只需要在./test 后面加一个取地址&就行了。


总结

本文我们只是简单的讲一些关于信号的概念性知识,目的是为了给大家引出后面的重点内容。所以都是一下简单的小点,理解起来还是比较容易的。

明天我将会给大家带来更详细的信号的内容。

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

相关文章:

  • 【读书笔记】《C++ Software Design》第七章:Bridge、Prototype 与 External Polymorphism
  • IPC框架
  • [2025CVPR]GNN-ViTCap:用于病理图像分类与描述模型
  • 晋升指南-笔记
  • 【Docker基础】Dockerfile指令速览:环境与元数据指令详解
  • React强大且灵活hooks库——ahooks入门实践之状态管理类hook(state)详解
  • 【C++】多线程同步三剑客介绍
  • AutoLabor-ROS-Python 学习记录——第一章 ROS概述与环境搭建
  • leetGPU解题笔记(1)
  • STM32-第六节-TIM定时器-2(输出比较)
  • 【芯片笔记】ADF4159
  • 【论文阅读】AdaptThink: Reasoning Models Can Learn When to Think
  • 【Java Stream】基本用法学习
  • sql初学见解
  • 2025上海市“星光计划“信息安全管理与评估赛项二三阶段任务书
  • Spring高级特性——反射和动态代理的性能优化
  • Python---上下文管理器
  • 移动端设备本地部署大语言模型(LLM)
  • 无需付费即可利用AI消除音频噪声和生成字幕
  • 浏览器渲染原理与性能优化全解析
  • 【零基础入门unity游戏开发——unity3D篇】3D光源之——unity反射和反射探针技术
  • 在线事务处理OLTP(Online Transaction Processing)负载是什么?
  • 08.如何正确关闭文件
  • QML 自定义Model基础之QAbstractListModel
  • iw 命令 -- linux 无线管理
  • python kivy 打包apk
  • Ampace厦门新能安科技Verify 测评演绎数字推理及四色测评考点分析、SHL真题题库
  • 入职华为od一个月的感受
  • 用 Node.js 构建模块化的 CLI 脚手架工具,从 GitHub 下载远程模板
  • 【Vue】浏览器缓存 sessionStorage、localStorage、Cookie