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

Linux学习笔记:信号

信号

  • 在Linux中什么是信号
  • 信号的产生方式
    • 硬件产生的信号
    • 软件产生的信号
    • 异常产生的信号
  • 进程对信号的处理
    • 信号的保存
    • 信号方法更改函数signal
      • 信号处理的更改
      • 恢复默认
      • 信号忽略
    • 信号的管理
      • 信号集 sigset_t
      • 对信号集的操作
    • 信号的捕捉过程

在Linux中什么是信号

在 Linux 系统中,信号是一种进程间通信的基本机制,用于通知进程发生了某种事件。
信号是一种软件中断,用于通知进程发生了某种事件。
这些事件可能包括硬件异常、用户输入、系统调用请求等。信号是异步发生的,即进程无法预测信号何时发生,但当信号发生时,系统会将信号发送给相应的进程。

在Linux中,信号一般被分为三大类:可以在bash使用kill -l 命令直接产看
在这里插入图片描述

  1. 标准信号(Standard Signals):由内核或进程向进程发送的信号,上图中的1-31号新号即为标准信号

  2. 实时信号(Real-time Signals):在标准信号的基础上引入了实时性概念,允许信号排队和按优先级传递,上图中的34-64即为实时信号

  3. 自定义信号(User-defined Signals):用户可以定义自己的信号类型,用于特定应用或通信需求。

信号的产生方式

无论信号有多少种产生方式,永远只能让OS向目标进程发送

硬件产生的信号

硬件产生的信号是由硬件设备或操作系统内核生成的,用于通知进程发生了某种事件。例如,当我们按下键盘上的^C键时,硬件会生成中断信号(SIGINT)来通知操作系统,然后操作系统将其传递给相应的进程

软件产生的信号

软件产生的信号是由进程自身或其他进程通过系统调用(如 kill )发送给目标进程的。这种方式允许进程之间进行通信和协作,例如向目标进程发送中断信号(SIGINT)以请求其终止执行:kill -9 pidnum

异常产生的信号

异常产生的信号是由硬件或操作系统检测到的异常事件引起的。例如,当进程执行非法指令、访问越界内存或发生浮点数异常时,硬件或操作系统会生成相应的信号(如 SIGILL、SIGSEGV、SIGFPE)来通知进程发生了异常情况。

进程对信号的处理

信号的保存

每个进程的PCB中都有一张自己的函数指针数组,一般被称为信号处理函数表,这个数组中的每个元素对应一个特定信号的处理函数。

当进程接收到信号时,操作系统会根据进程的PCB中的信号处理函数表找到对应的处理函数,并执行相应的逻辑。

以下是对信号处理的几个概念:

  1. 信号递达:实际信号的处理动作,一般有三种:默认,忽略,自定义
  2. 信号未决(pending):信号从产生到递达之间的状态,即在信号的位图中时,一斤产生但未被处理时的状态
  3. 信号阻塞(block):信号时允许被阻塞的,信号产生了,但暂时不进行递达的信号就是阻塞信号

因此操作系统会在进程PCB中创建三个表,用于对信号的状态进行记录,
其中,block表记录的是对应位置信号是否被屏蔽
pending表记录的是对应位置信号是否未决
handler表记录的事对应位置信号的执行方式
在这里插入图片描述

信号方法更改函数signal

信号处理的更改

在Linux中,信号处理函数 (signal) 是一种用来处理异步事件的方法。
信号是一个软件中断,通常由操作系统生成,用来通知程序某个事件已经发生,例如:非法操作、外部中断、定时器溢出等。

原型如下:

void (*signal(int signum, void (*handler)(int)))(int);

两个参数:

  1. signum:表示要设置的信号编号
  2. handler:表示要设置的信号处理函数,可以是一个函数指针,一般来说是我们自己写的一个函数,将signum所表示的信号重新实现

注意事项

  • 可重入性:信号处理函数应该是可重入的,即它们应该避免使用全局状态和执行非原子操作。
  • 限制:在信号处理函数中,只有少数几个函数是安全可调用的(通常称为异步信全函数)。例如,大多数系统调用和库函数都不应该在信号处理函数中调用。

举例:这是一个将2号信号进行更改,原本应该执行的功能被我修改成了handler函数内的内容

#include<iostream>
#include<signal.h>
#include<unistd.h>void handler(int signo)
{std::cout<< "获得一个" << signo << "号信号" << std::endl;exit(1);
}int main()
{signal(2,handler);return 0;
}

恢复默认

如果在开发过程中,忘记了自己之前对某个信号的执行更改,可以将signal函数的第二个参数传入宏:SIG_DFL来使得信号执行它默认的功能

signal(2,SIG_DFL);

信号忽略

在程序开发中,如果想要忽略某个信号,可以直接将signal函数的第二个参数传参宏:SIG_IGN

signal(2,SIG_IGN);

信号的管理

为了高效地处理多个信号,因此要先描述,再组织 , Linux提供了信号集的概念,使得可以将多个信号组合在一起进行处理。

信号集 sigset_t

sigset_t是一个用于表示信号集的数据类型,它通常定义在<signal.h>头文件中。
原型:

typedef struct sigset_t {unsigned long sig[_NSIG / sizeof(long)];
} sigset_t;

其中,_NSIG是一个宏,表示系统中定义的信号总数。sigset_t类型的信号集用于保存一个或多个信号的集合,可以通过位运算来操控信号集。

对信号集的操作

  1. 要创建一个空的信号集,可以使用以下代码:
sigset_t empty_set;
sigemptyset(&empty_set);

这样就有了一个新的信号集,这将清除empty_set中的所有信号位,使其成为一个空集。

  1. 创建一个全满的信号集:
sigset_t full_set;
sigfillset(&full_set);

这样就可以创建一个全满的信号集,并且将full_set中的所有信号位设置为1,表示设置了所有可能的信号。

  1. 设置或查询进程的信号前景,就好像设置权限掩码一样,对信号这些信号在进程处于等待状态(如在 select、poll、epoll_wait 等系统调用中)时会被优先处理:
void sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

其中,how参数表示拷贝的方式,可以是SIG_BLOCK、SIG_UNBLOCK或SIG_SETMASK。set参数指向要拷贝的信号集,oldset参数用于接收旧的信号集。

  1. 添加信号集:
void sigaddset(sigset_t *set, int signum);

该函数将signum信号的位添加到set信号集中。

  1. 清除信号集:
void sigdelset(sigset_t *set, int signum);

该函数将signum信号的位从set信号集中删除。

  1. 检查信号是否存在于信号集中:
int sigismember(const sigset_t *set, int signum);

返回 1:如果指定的信号 signum 在信号集 set 中。
返回 0:如果指定的信号 signum 不在信号集 set 中。
返回 -1:如果发生错误(例如指定的信号编号无效),并且设置全局变量 errno

  1. 查询当前进程等待处理的信号集合,也就是查询处于pending状态的信号集合.这个函数可以帮助进程了解有哪些信号已经被生成但尚未被处理。
int sigpending(sigset_t *set);

当 sigpending 函数被调用时,它会将当前进程的信号等待集合(即那些已经被生成但尚未被处理或阻塞的信号)复制到 set 指向的 sigset_t 变量中。这样,进程就可以通过检查 set 中的信号位来确定有哪些信号需要处理。

下面是一个代码示例,我们首先使用 sigprocmask 函数屏蔽了 SIGINT 信号。然后,我们让进程睡眠5秒钟,以便有足够的时间让用户按下 Ctrl+C。在睡眠之后,我们调用 sigpending 函数来查询当前进程等待的信号。如果 SIGINT 信号在等待队列中,我们将打印出相应的信息。最后,我们使用 sigprocmask 函数恢复到旧的信号掩码,以便进程可以正常处理信号。

#include <signal.h>
#include <unistd.h>
#include <stdio.h>int main() {sigset_t pending_mask, empty_mask, old_mask;// 创建一个信号集合,用于存储 `SIGINT`sigemptyset(&empty_mask);sigaddset(&empty_mask, SIGINT); // 添加 SIGINT 到屏蔽集合// 阻止 SIGINT 信号if (sigprocmask(SIG_BLOCK, &empty_mask, &old_mask) == -1) {perror("sigprocmask");return 1;}printf("SIGINT 信号已被屏蔽,现在我将进入睡眠状态。\n");// 睡眠一段时间,以便有机会生成 SIGINT 信号sleep(5);// 查询当前进程等待的信号if (sigpending(&pending_mask) == -1) {perror("sigpending");return 1;}// 打印等待的信号if (sigismember(&pending_mask, SIGINT)) {printf("SIGINT 信号正在等待处理。\n");} else {printf("没有信号在等待处理。\n");}// 恢复旧的信号掩码if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {perror("sigprocmask");return 1;}return 0;
}

信号的捕捉过程

如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。
但是自定义信号处理函数是我们自己写的,是存在于用户空间的,因此这里涉及到一个用户到内核的转换问题,因为用户并不具有所有的操作权限,下面的图片可以很清楚的表达出信号捕捉过程中用户和内核态的转化过程
在这里插入图片描述
图片来自必应搜索

相关文章:

Linux学习笔记:信号

信号 在Linux中什么是信号信号的产生方式硬件产生的信号软件产生的信号异常产生的信号 进程对信号的处理信号的保存信号方法更改函数signal信号处理的更改恢复默认信号忽略 信号的管理信号集 sigset_t对信号集的操作 信号的捕捉过程 在Linux中什么是信号 在 Linux 系统中&…...

C#中的隐式类型转换和显式类型转换

在C#中&#xff0c;类型转换分为隐式类型转换&#xff08;Implicit Type Conversion&#xff09;和显式类型转换&#xff08;Explicit Type Conversion&#xff09;&#xff0c;也称为隐式转换和强制转换。 隐式类型转换&#xff08;Implicit Type Conversion&#xff09; 隐…...

linux上如何排查JVM内存过高?

在Linux上排查JVM内存过高的问题&#xff0c;可以采用以下几种方法&#xff1a; 1. **使用top命令查看进程**&#xff1a;通过top命令可以观察到系统中资源占用情况&#xff0c;包括CPU和内存。当收到内存过高的报警时&#xff0c;可以使用top命令来查看是哪个进程的内存使用率…...

第四届上海理工大学程序设计全国挑战赛 J.上学 题解 DFS 容斥

上学 题目描述 usst 小学里有 n 名学生&#xff0c;他们分别居住在 n 个地点&#xff0c;第 i 名学生居住在第 i 个地点&#xff0c;这些地点由 n−1 条双向道路连接&#xff0c;保证任意两个地点之间可以通过若干条双向道路抵达。学校则位于另外的第 0 个地点&#xff0c;第…...

word-排版文本基本格式

1、文本的基本格式&#xff1a;字体格式、段落格式 2、段落&#xff1a;word排版的基本控制单位 3、每敲一次回车&#xff0c;为一个段落标记&#xff0c;注意区分换行符和段落标记&#xff0c;换行符为指向下的箭头&#xff0c;段落标记为带拐弯的箭头&#xff0c;换行符&…...

目标检测YOLO实战应用案例100讲-无监督领域自适应目标检测方法研究与应用(五)

目录 多源无监督领域自适应目标检测方法 4.1研究现状及问题形成 4.2相关工作详述...

通过python实现Google的精准搜索

问题背景&#xff1a; 我想通过Google或者其他网站通过精准搜索确认该产品是否存在&#xff0c;但是即使该产品不存在Google也会返回一些相关的url链接&#xff0c;现在想通过python实现搜索结果的精准匹配以确认该产品是否为正确的名称【可以通过google搜索到&#xff0c;如果…...

Nios-II编程入门实验

文章目录 一 Verilog实现流水灯二 Nios实现流水灯2.1 创建项目2.2 SOPC添加模块2.3 SOPC输入输出连接2.4 Generate2.5 软件部分2.6 运行结果 三 Verilog实现串口3.1 代码3.2 引脚3.3 效果 四 Nios2实现串口4.1 sopc硬件设计4.2 top文件4.3 软件代码4.4 实现效果 五 参考资料六 …...

从0开始学python(七)

目录 前言 1 break、continue和pass函数 1.1 break 1.2 continue 1.3 pass 2、序列的索引及切片操作 2.1字符串的索引和切片 2.1.1 字符串索引 2.1.2 字符串切片 总结 前言 上一篇文章我们介绍了python中的循环结构&#xff0c;包括for和while的使用。本章接着往下讲。…...

【二叉树算法题记录】404. 左叶子之和

题目描述 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 题目分析 其实这题无论是迭代法还是递归法&#xff0c;最重要的是要明确判断左叶子的条件&#xff1a;当前节点有左孩子&#xff0c;且这个左孩子没有它的左孩子和右孩子。 迭代法 感觉只要二叉树相关…...

面试集中营—Spring篇

Spring 框架的好处 1、轻量&#xff1a;spring是轻量的&#xff0c;基本的版本大约2MB&#xff1b; 2、IOC&#xff1a;控制反转&#xff0c;Spring的IOC机制使得对象之间的依赖不再需要我们自己来控制了&#xff0c;而是由容易来控制&#xff0c;一个字&#xff1a;爽&#xf…...

Lia 原理

训练阶段 论文流程&#xff1a; 具体实现&#xff1a; 通过latent space传递运动信息,实现分两部分。 1&#xff09;image space->latent space 将源图像映射到隐空间编码。X_s (source image )映射到编码Z_sr&#xff0c;通过W_rd方向上的变化&#xff0c;得到新的编码Z…...

文本批量操作技巧:内容查找不再繁琐,自动化批量移动至指定文件夹

在文本处理和信息管理的日常工作中&#xff0c;我们经常需要处理大量的文件和数据。面对这些海量的信息&#xff0c;如何快速而准确地查找特定的内容&#xff0c;并将它们批量移动至指定的文件夹&#xff0c;成为了一项关键的技能。本文将介绍办公提效工具一些实用的文本批量操…...

[数据结构]动画详解单链表

&#x1f496;&#x1f496;&#x1f496;欢迎来到我的博客&#xff0c;我是anmory&#x1f496;&#x1f496;&#x1f496; 又和大家见面了 欢迎来到动画详解数据结构系列 用通俗易懂的动画的动画使数据结构可视化 先来自我推荐一波 个人网站欢迎访问以及捐款 推荐阅读 如何低…...

图片批量管理迈入智能新时代:一键输入关键词,自动生成并保存惊艳图片,轻松开启创意之旅!

在数字化时代&#xff0c;图片已成为我们表达创意、记录生活、传递信息的重要工具。然而&#xff0c;随着图片数量的不断增加&#xff0c;如何高效、便捷地管理这些图片&#xff0c;却成为了一个令人头疼的问题。 第一步&#xff0c;进入首助编辑高手主页面&#xff0c;在上方…...

【硬件模块】ESP-01SWiFi模块基于AT指令详解(WiFi,TCP/IP,MQTT)

ESP-01S ESP-01S是由安信可科技开发的一款Wi-Fi模块。其核心处理器是ESP8266&#xff0c;该处理器在较小尺寸的封装中集成了业界领先的Tensilica L106超低功耗32位微型MCU&#xff0c;带有16位精简模式&#xff0c;主频支持80MHz和160MHz&#xff0c;并集成了Wi-Fi MAC/BB/RF/P…...

数据结构之单单单——链表

目录 一.链表 1&#xff09;链表的概念 2&#xff09;链表的结构 二.单链表的实现 三.链表的分类 1&#xff09;单向或者双向 2&#xff09;带头或不带头 3&#xff09;循环或非循环 一.链表 1&#xff09;链表的概念 链表&#xff08;Linked List&#xff09;是一种…...

【Linux笔记】 基础指令(二)

风住尘香花已尽 日晚倦梳头 重命名、剪切指令 -- mv 简介&#xff1a; mv 命令是 move 的缩写&#xff0c;可以用来移动文件或者将文件改名&#xff0c;是 Linux 系统下常用的命令&#xff0c;经常用来备份文件或者目录 语法&#xff1a; mv [选项] 源文件或目录 目标文件或目录…...

软件全套资料梳理(需求、开发、实施、运维、安全、测试、交付、认证、评审、投标等)

软件全套精华资料包清单部分文件列表&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说明书&#xff0c;需求调研计划&#xff0c;用户需求调查单&#xff0c;用户需求说明书&#xff0c;概要设计说明书&#xff0c…...

javacv实时解析pcm音频流

javacv实时解析pcm音频流 解析代码 try (ByteArrayInputStream inputStream new ByteArrayInputStream(bytes);){FFmpegFrameGrabber grabber new FFmpegFrameGrabber(inputStream);// PCM S16LE 格式grabber.setFormat("s16le");// 采样率grabber.setSampleRate(1…...

Matlab|考虑极端天气线路脆弱性的配电网分布式电源和储能优化配置模型

1主要内容 程序主要参考《考虑极端天气线路脆弱性的配电网分布式电源配置优化模型-马宇帆》&#xff0c;针对极端天气严重威胁配电网安全稳定运行的问题。基于微气象、微地形对配电网的线路脆弱性进行分析&#xff0c;然后进行分布式电源接入位置与极端天气的关联性分析&#…...

【Python基础】装饰器(3848字)

文章目录 [toc]闭包什么是装饰器装饰器示例不使用装饰器语法使用装饰器语法 装饰器传参带参数的装饰器类装饰器魔术方法\__call__()类装饰器示例带参数类装饰器property装饰器分页操作商品价格操作 个人主页&#xff1a;丷从心 系列专栏&#xff1a;Python基础 学习指南&…...

十、Redis内存回收策略和机制

1、Redis的内存回收 在Redis中可以设置key的过期时间&#xff0c;以期可以让Redis回收内存&#xff0c;循环使用。在Redis中有4个命令可以设置Key的过期时间。分别为 expire、pexpire、expireat、pexpireat。 1.1、expire expire key ttl&#xff1a;将key的过期时间设置为tt…...

Ansible --- playbook 脚本+inventory 主机清单

一 inventory 主机清单 Inventory支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或 多个主机组内。 如果是名称类似的主机&#xff0c;可以使用列表的方式标识各个主机。vim /etc/ansible/hosts[webservers]192.168.10.1…...

【hive】transform脚本

文档地址&#xff1a;https://cwiki.apache.org/confluence/display/Hive/LanguageManualTransform 一、介绍二、实现1.脚本上传到本地2.脚本上传到hdfs 三、几个需要注意的点1.脚本名不要写全路径2.using后面语句中&#xff0c;带不带"python"的问题3.py脚本Shebang…...

5款可用于LLMs的爬虫工具/方案

5款可用于LLMs的爬虫工具/方案 Crawl4AI 功能: 提取语义标记的数据块为JSON格式&#xff0c;提供干净的HTML和Markdown文件。 用途: 适用于RAG&#xff08;检索增强生成&#xff09;、微调以及AI聊天机器人的开发。 特点: 高效数据提取&#xff0c;支持LLM格式&#xff0c;多U…...

投影、选择转SQL语言

使用以下两个表进行举例&#xff0c;第一个表为R表&#xff0c;第二个表为S表 R.AR.BR.C123456789 S.AS.BS.C101112131415161718 1、投影转SQL语言&#xff1a; 兀 A,B,C (R) 等价于select A,B,C from R 解释&#xff1a; 兀&#xff1a;相当于select (R):相当于from R…...

系统加固-自用

一、windows 1、概述 (1)、权限最高&#xff1a;system(系统账户)&#xff0c;权限比administrator权限还高 (2)、常见操作系统安全漏洞类型 缓冲区溢出漏洞TCP/IP协议漏洞web应用安全漏洞开放端口的安全漏洞 2、系统安全加固方法 (1)、系统不显示上次登录的用户名 进入…...

Java面试题:阐述Java中的自动装箱与拆箱机制,以及使用它们时可能遇到的性能问题

在Java中&#xff0c;自动装箱&#xff08;Autoboxing&#xff09;和拆箱&#xff08;Unboxing&#xff09;是Java 5引入的特性&#xff0c;它们允许基本数据类型和对应的包装类之间的自动转换。 自动装箱 自动装箱是指将基本数据类型&#xff08;如int、double等&#xff09…...

初识sql注入--手工注入

目录 可能使用的sql函数 入侵网站方式 1、文件上传漏洞 2、rce 3、sql注入 SQL注入 什么是sql注入 进行SQL注入 实验环境 开始实验&#xff08;使用information_shema数据库&#xff09; 1、进入靶场 2、报列数 下面来解释一下为什么要照上面SQL语句写 url编码 单…...