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;
}

信号的捕捉过程

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/603014.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python中tkinter编程入门1

1 tkinter库简介 tkinter是Python的标准库&#xff0c;用来进行GUI&#xff08;Graphical User Interface&#xff0c;图形用户界面&#xff09;编程。 2 导入tkinter库 tkinter是Python默认的GUI库&#xff0c;因此&#xff0c;IDLE中已经包含了该库&#xff0c;使用时无需…

在uniapp中如何安装axios并解决跨域问题

目录 1、安装axios 2、导入 3、使用&#xff08;发请求&#xff09; 2.解决跨域问题 1.为什么要解决跨域问题&#xff1f; 2.前端如何解决跨域问题&#xff1f; 1、安装axios npm install axios 2、导入 在main.js中导入使用 import axios from axios; // 创建一个名…

男士内裤什么品牌质量好?男士内裤选购指南攻略分享

有很多小伙伴认为男士内裤只是穿在里面的&#xff0c;只要能穿就不讲究了。但实际上选择一些质量不好的男士内裤会让穿着舒适性十分不佳&#xff0c;同时还会因为不具备抗菌效果而滋生细菌&#xff0c;导致出现健康问题。 最近我也是深入研究了一番关于男士内裤&#xff0c;今天…

旺店通·企业奇门与金蝶云星空对接集成订单查询打通销售订单新增

旺店通企业奇门与金蝶云星空对接集成订单查询打通销售订单新增 对接源平台:旺店通企业奇门 慧策最先以旺店通ERP切入商家核心管理痛点——订单管理&#xff0c;之后围绕电商经营管理中的核心管理诉求&#xff0c;先后布局流量获取、会员管理、仓库管理等其他重要经营模块。慧策…

该怎么发外贸开发信才能瞄准大客户?

1.要知道80%的业务源自于大客户&#xff0c;要合理利用自己的时间。其实我自己发邮件一直都是粗发模式&#xff0c;效果也还可以&#xff0c;主要是因为我的客户都是展会上的&#xff0c;所以拒收和失败率会很低&#xff0c;而且客户意向度一直很高&#xff0c;但是花费的时间精…

泉州晋江厦门拉货最便宜的7个方式,建议收藏

众所周知&#xff0c;搬家、拉货的时间长、距离长&#xff0c;运费也比较贵。面对不菲的费用&#xff0c;很多人会比较谨慎&#xff0c;先网上搜搬家攻略&#xff0c;一番对比以后&#xff0c;找到最便宜的运输方式。那怎么运输最便宜最放心呢&#xff1f; 方式一&#xff1a;找…

[MDK] 介绍STM32使用C和C++混合编程的方法

目录 [MDK] 介绍STM32使用C和C混合编程的方法前言业务场景步骤1基础工程步骤2写代码步骤3添加cpp文件步骤4配置与编译上机现象后记 [MDK] 介绍STM32使用C和C混合编程的方法 前言 搞单片机编程大多数还是使用MDK编程&#xff0c;自己对MDK这个软件也比较熟悉&#xff0c;在网络…

【RAG 论文】Dense X 检索:将“命题”作为检索粒度

论文&#xff1a;Dense X Retrieval: What Retrieval Granularity Should We Use? ⭐⭐⭐⭐ Code: github.com/ct123098/factoid-wiki 文章目录 一、论文速读二、命题&#xff08;Proposition&#xff09;三、FactoidWiki四、实验及分析4.1 Passage Retrieval 任务4.2 Open-Do…

前端css中径向渐变(radial-gradient)的使用

前端css中径向渐变的使用 一、前言二、主要内容说明&#xff08;一&#xff09;、径向渐变的形状1.椭圆形渐变&#xff08;ellipse&#xff09;&#xff0c;源码12.源码1运行效果3.圆形渐变&#xff08;circle&#xff09;&#xff0c;源码24.源码2运行效果 &#xff08;二&…

遇到螺纹连接过程中的软连接,怎么办?——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 在螺纹连接过程中遇到软连接时&#xff0c;首先需要明确软连接的概念及其特点。软连接通常指的是在螺栓拧紧过程中&#xff0c;由于紧固件与被连接件之间的材料、表面状况或装配工艺等因素&#xff0c;导致拧紧力矩不能…

分布式关系型数据库管理系统 OceanBase 安装和配置教程

&#x1f30a; 分布式关系型数据库管理系统 OceanBase 安装和配置教程 &#x1f680; 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝…

Kubernetes核心概念基本操作

1.1 Namespace命名空间 1.1.1 Namespace核心概念 Kubernetes 的 Namespace&#xff08;命名空间&#xff09;是一种用于创建逻辑隔离分区的机制&#xff0c;它的主要作用是用来实现多套环境的资源隔&#xff0c;它允许用户在同一个物理集群中模拟出多个虚拟集群的效果。以下是…

APP广告变现:自刷的秘密与规则

在移动互联网时代&#xff0c;广告已成为众多APP盈利的主要方式之一。对于开发者和运营者而言&#xff0c;如何通过广告变现提高收益是他们必须关注的问题。然而&#xff0c;在众多的变现方法中&#xff0c;“自刷广告”这一概念可能让一些人感到迷惑。实际上&#xff0c;只要在…

在Mars3d实现cesium的ImageryLayer自定义瓦片的层级与原点

需要自定义瓦片层级和原点&#xff0c;所以需要自己写第三方图层&#xff0c;但是之前写的很多方法&#xff0c;图层控制和显隐以及透明度&#xff0c;需要跟之前的交互一直&#xff0c;改动量太大的话不划算&#xff0c;所以直接看Mars3d的layer基类&#xff0c;把重写的image…

python词云图背景颜色修改

python词云图背景颜色修改 词云图介绍wordcloud介绍修改背景颜色 词云图介绍 词云图&#xff08;Word Cloud&#xff09;是一种文本数据的可视化表示形式&#xff0c;它通过字体大小、颜色、布局等视觉元素来展示文本中不同词汇的频率或重要性。词云图中&#xff0c;出现频率高…

怎么清理服务器的C盘?

有时候我们经常会遇到C盘被占满的情况&#xff0c;C盘被占满的原因有很多&#xff0c;下面我们就来分析下有可能导致C盘占满的原因&#xff1a; 第一种情况&#xff1a;中毒 打开服务器任务管理器选择进程&#xff0c;并且勾选显示所有用户的进程&#xff0c;我们可以点击映像…

PHPStudy 下载PHP提示“当前网络不稳定,下载失败”

错误信息 当前网络不稳定&#xff0c;下载失败 获取下载链接失败&#xff0c;请检查网络 假查网络 问题原因 xp.cn服务器的网络不稳定&#xff0c;不是你电脑的网络问题。 解决办法 第一步&#xff1a;下载现成的PHP文件 直接下载现成的文件&#xff0c;放到php目录。 将…

FlashAttention(flash-attn)安装

FlashAttention&#xff08;flash-attn&#xff09;安装 Flash Attention是一种注意力算法&#xff0c;用于减少这一问题&#xff0c;并更有效地缩放基于转换器的模型&#xff0c;从而实现更快的训练和推理。标准注意力机制使用高带宽内存&#xff08;HBM&#xff09;来存储、…

写一个函数返回参数二进制中1的个数--四种方法及原理解释

虽然本方法是java写的&#xff0c;但是其原理适用于大部分语言 方法一&#xff1a;通过取模%运算取出每一位比特位数值&#xff0c;再进行判断&#xff08;该方法不可判断负数&#xff09; 原理&#xff1a; 通过取模num % 2 1 取出该数的每一个二进制位数&#xff0c;再判…

Python selenium

1.搭建环境 1.安装&#xff1a; pip install msedge-selenium-tools 不要使用pip install selenium&#xff0c;我的电脑上没法运行 2.下载驱动 Microsoft Edge WebDriver |Microsoft Edge 开发人员 edge浏览器点设置---关于即可找到版本号&#xff0c;一定要下载对应版…