Linux——信号(2)

news2024/11/27 22:31:19
在上一张博客我们介绍了Linux中信号的概念和信号是如何产生的,虽然信号
有多种产生方式,但是最终只能由操作系统给对应进程发送特定信号。现在
我将更加规范的介绍Linux中的信号。

上一章的遗留问题

我们上一章中在观察信号的默认处理的时候发现终止信号的种类可以分为两种,Term和Core:
在这里插入图片描述
我们可以发现Core类信号产生的异常错误的严重程度是要高于Term类型的。而且出现了Core类错误时,我们在修复错误时往往是需要修改代码本身的。所以Core类型的信号在被处理时,同时也会生成一个文件,这个文件的文件名包含Core和出现异常的进程pid,这个文件保存了进程出异常时,进程中的一些重要的数据:
如果是使用虚拟机的小伙伴可能会观察到这种文件。但是使用云服务器的小伙伴可能并没有见过这种文件,我们可以使用ulimit -a查看系统的一些配置的大小,在云服务器上:
在这里插入图片描述
可以看到云服务器上这个文件的大小被设置成了0,那也就是相当于不生成这种文件。而在虚拟机中这个文件的大小不一定是被设置成了0。我们可以使用ulimit -c来修改这个文件配置的大小:
在这里插入图片描述
我们设置好文件配置的大小之后我们写一段代码:
在这里插入图片描述
我们再重新起一个shell然后再运行这个程序,再本来这个shell上也运行一遍:
新的shell进程上:
在这里插入图片描述
可见它并没有生成什么包含core和进程pid的文件。
本来的shell进程上:
在这里插入图片描述
它生成了这样的一个文件,那为什么新起的shell进程上没有生成呢?我们发现在新起的shell进程上:
在这里插入图片描述
它的大小仍旧是0,至此我们可以得出使用ulimit -c修改的配置文件的大小,它的作用效果是随shell进程的。
那么这个文件有什么用呢?我们打开它可以看到它就是二进制:
在这里插入图片描述
我们说了,它其中会记录进程中的一些重要的数据。这使得我们可以使用gdb来便捷的定位到哪句代码出了问题:
在这里插入图片描述
这种技术叫做核心转储。
那么为什么云服务器会将它的大小设置为0不让它生成呢?我们可以看到,这个文件是比较大的,假如我们多生成几个呢?
在这里插入图片描述
这还只是一行代码,如果是公司企业中的服务器代码呢?我们都知道服务器中的服务上线之后,会有运维人员来保证服务器中服务的正常运行,而现在也有自动化运维,它可以在进程异常退出之后,可以重新让这个服务跑起来,那么此时此刻对于我们现在这个代码,它每一次启动都会带来那么大的文件,我们的代码可能一秒就启动上千次,那么这样的话,我们的磁盘用不了多久就被写满了,这对我们要修复异常的服务就更加的困难了,磁盘满了之后我们一般是对这台机器做不了任何操作了。

1. 一些规范的名词

信号递达:实际执行信号的处理动作
信号未决:信号从产生到递达之间的状态
阻塞:处于信号未决和信号递达之间的状态,其实也是一直处于信号未决状态,直到信号
被停止阻塞,然后才会递达

信号递达其实就是处理信号,普通信号的信号是不会叠加的,它产生多少次也只算一次,递达前后未决状态就会被取消,无论之前有多少次信号未决,这也跟位图本身的特性有关。
信号未决其实就是信号的产生也就是task_struct结构体中的信号位图被写入
我们以前介绍过,对于信号的处理方式有三种:默认处理,忽略,自定义捕捉。其中我们要清楚忽略它本身也是对于信号的处理方式(例如老师布置了作业之后,你选择视而不见这本身也是对这件事情的一个处理方式,你听到了老师布置作业叫做信号未决,你写作业就叫做信号递达。你对老师布置作业这条消息视而不见忽略也叫做信号递达,因为你处理了这个信号)。
有些人会将忽略和阻塞混淆成一个东西这是不对的,阻塞是只要信号只要被阻塞后就不会被递达,而忽略是这个信号已经递达了。两者截然不同。
在前面我介绍了信号的自定义捕捉使用signal接口,这里我介绍信号的默认处理以及忽略,它们是由两个宏实现的:
信号默认处理:
在这里插入图片描述
在这里插入图片描述
在这段代码中我们开始将二号信号设置成自定义捕捉,在信号递达时将进行我们自定义的函数,会打印出如上结果,但是当cnt–到小于0时我们将2号信号更改为默认处理,此时我们ctrl + c就会直接退出进程,其中SIG_DFL就是将信号设置成默认处理方式的宏。
忽略处理:
在这里插入图片描述
在这里插入图片描述
SIG_IGN是将信号忽略的宏,可以看到当我们使用ctrl + c的组合键终止进程的时候并没有任何反应,使用ctrl + \才终止了进程。
观察这两个宏的定义其实它们就是强转而已:
在这里插入图片描述

2. 内核数据结构

a. 内核数据结构

我们在之前学会了如何对信号进行自定义捕捉也就是信号递达,但是我们对信号未决的认识并不是那么那么清楚,其实在内核数据结构中,我们的task_struct关于信号维护着这么些东西:
在这里插入图片描述
其中hander表就是一个函数指针数组,下标对应着信号的编号,其中有着对应信号的处理方式。而pending表就是信号产生时要被写入的位图表,block是从结构上与pending表一模一样的,不同的是:
pending中的位表示信号的编号,pending的内容表示信号是否未决。
而block中的位表示信号的编号,block的内容表示是否都阻塞该信号。
我们学会了信号递达的处理方式,现在我们要来学习关于信号未决和信号阻塞。其中主要是信号阻塞,因为信号未决也就是我前面介绍的信号的产生方式嘛。
对于block表和pending表它们其实都是位图,而在Linux中,给出了这样的结构:
在这里插入图片描述
在这里插入图片描述
sigset_t这种类型叫做信号集
其中block表也叫做阻塞信号集,当前进程的信号屏蔽字

b. 信号集操作函数

那么我们如何对这个位图进行操作呢?难道得自己造轮子吗其实操作系统早就帮我们造好了:
在这里插入图片描述
下面我们来介绍一下,这些对sigset_t类型的位图操作的函数

1. sigemptyset:清空set(全部置零,也就是初始化)
2. sigfillset:全部置一
3. sigaddset:将目标信号对应位图的位置置一
4. sigdelset:将目标信号对应位图的位置置零
5. sigismember:检测目标信号是否在set表中

c. block操作接口

了解了关于sigset_t类型的操作后,我们再来认识关于对block表的操作接口,其实就一个
sigprocmask:
在这里插入图片描述
其中第一个参数是操作方式:

1. SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字的信号
2. SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字中解除阻塞的信号
3. SIG_SETMASK:设置当前信号屏蔽字位为set所指向的值,即block表 = set

第二个参数是我们要设置的set表
第三个参数是被更新前的block表,是一个输出型参数。

d. pending表接口

关于pending表其实就是信号的产生,我们之前已经介绍过了,所以这里只有一个接口,那就是获取pending表:
在这里插入图片描述
可以看到它有一个输出型参数。
有了这些接口之后,我们就可以写出代码来观测,内核数据结构的表现了:

e. 代码展示

在这里插入图片描述

在这里插入图片描述

我们可以看到当启动进程的时候,我们按下ctrl + c之后,信号未决后就信号递达了,五秒过后,我们阻塞了二号信号,此时按下ctrl + c之后,虽然pending表中二号信号处于信号未决的状态,但是它无法信号递达,当再过五秒之后取消对二号信号的阻塞,二号信号立即递达,递达的同时pending表中对应二号信号的信号未决状态也取消了。
附上代码:

#include <iostream>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

using namespace std;

void sighander(int signo)
{
  cout << "获得了" << signo << "号信号" << endl;
}

void PrintPending()
{
  sigset_t pending;
  sigpending(&pending); // 获取pending表
  for(int i = 31; i > 0; i--)
  {
    if(sigismember(&pending, i)) // 利用该函数判断特定信号是否存在于pending表中,存在则打印1,不存在打印0
    {
      cout << 1;
    }
    else cout << 0;
  }
  cout << endl;
}


int main()
{
  sigset_t set, oset;

  // 将要使用的set表初始化
  sigemptyset(&set);
  sigemptyset(&oset);
  signal(2, sighander); // 对2好信号自定义捕捉


  int cnt = 5;
  while(true)
  {
    PrintPending(); // 打印pending表
    sleep(1);
    cnt--;

    if(cnt == 0)
    {
      sigaddset(&set, 2);
      sigprocmask(SIG_BLOCK, &set, &oset); // 对2号信号进行阻塞
      cout << "屏蔽了二号信号" << endl;
    }

    if(cnt == -5)
    {
      sigprocmask(SIG_SETMASK, &oset, &oset); // 取消对2号信号的阻塞
      cout << "取消屏蔽二号信号" << endl;
    }
  }
  return 0;
}

还有人会有疑问,那就是到底是信号未决状态的取消是在信号递达开始前还是完成后呢?在信号递达的时候显然是不可能的,因为当自定义捕捉时,我们可没有取消信号未决状态。
一个简单的代码可以看到:

#include <iostream>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

using namespace std;

void PrintPending()
{
  sigset_t pending;
  sigpending(&pending); // 获取pending表
  for(int i = 31; i > 0; i--)
  {
    if(sigismember(&pending, i)) // 利用该函数判断特定信号是否存在于pending表中,存在则打印1,不存在打印0
    {
      cout << 1;
    }
    else cout << 0;
  }
  cout << endl;
}

void sighander(int signo)
{
  PrintPending();
  cout << "获得了" << signo << "号信号" << endl;
}

int main()
{
  signal(2, sighander);

  while(true)
  {
    cout << "running..." << endl;
    sleep(1);
  }
  return 0;

在这里插入图片描述
可以看到在信号递达前就已经解除信号未决状态了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE4 C++联网RPC教程笔记(一)(第1~4集)

UE4 C联网RPC教程笔记&#xff08;一&#xff09;&#xff08;第1~4集&#xff09; 前言1. 教程介绍与资源2. 自定义 Debug 功能3. Actor 的复制4. 联网状态判断 前言 本系列笔记将会对梁迪老师的《UE4C联网RPC框架开发吃鸡》教程进行个人的知识点梳理与总结&#xff0c;此课程…

软考29-上午题-排序

一、排序的基本概念 1-1、稳定性 稳定性指的是相同的数据所在的位置经过排序后是否发生变化。若是排序后&#xff0c;次序不变&#xff0c;则是稳定的。 1-2、归位 每一趟排序能确定一个元素的最终位置。 1-3、内部排序 排序记录全部存放在内存中进行排序的过程。 1-4、外部…

白话微机:6.解释RTOS以及一些考研面试问题

一. 前言&#xff08;总结世界观&#xff09; 很久很久以前&#xff0c;有这样一个世界&#xff0c;这个世界有着现实世界一样的元素&#xff1a;那里的人又有一个别的名字叫做“数据”&#xff0c;人有0有1&#xff1b;人们也有住房&#xff0c;这些住房在这个世界叫做“存储器…

C++-opencv的imread、imshow、waitkey、namedWindow

在C中使用OpenCV时&#xff0c;imread和imshow是两个非常基础且常用的函数&#xff0c;用于读取图像和显示图像。以下是这两个函数的简要说明和如何一起使用它们的示例。 imread函数 imread用于从指定的文件路径读取图像。它将图像读入为cv::Mat对象&#xff0c;这是OpenCV中…

单机环境搭建Redis伪集群

1、Redis版本 [rootwsdhla ~]# redis-server -v Redis server v6.2.6 sha00000000:0 mallocjemalloc-5.1.0 bits64 buildbf23dac15dfc00fa[rootwsdhla ~]# redis-cli -v redis-cli 6.2.62、创建节点目录 创建6个节点目录&#xff0c;分别复制一份redis.conf并编辑&#xff1a…

关于Sora的一些紧迫问题...

OpenAI Sora 概述 OpenAI最新的创新&#xff0c;Sora&#xff0c;在人工智能领域开辟了新的天地。Sora是一个文本到视频的扩散模型&#xff0c;可以将文本描述转化为逼真的视频内容。它解决了一个重大的技术挑战&#xff0c;即在视频中保持主体的一致性&#xff0c;即使它们暂…

anomalib1.0学习纪实-续2:三个文件夹

为了读懂程序&#xff0c;有三个最重要的文件夹&#xff0c;如下图&#xff1a; 正好对应四个类&#xff0c;如下图&#xff1a; 四个类的来源如下图所示&#xff1a; 注意&#xff0c;MVTec是个大类&#xff0c;里面用到了这里的第四个类MVTecDataset&#xff0c;代码如下。…

Windows制作Ubuntu的U盘启动盘

概要&#xff1a; 本篇演示在Windows10中制作Ubuntu22.04的U盘启动盘 一、下载Ubuntu22.04的iso文件 在浏览器中输入https://ubuntu.com去Ubuntu官网下载Ubuntu22.04的iso文件 二、下载Ultraiso 在浏览器中输入https://www.ultraiso.com进入ultraiso官网 点击FREE TRIAL&a…

设计模式复习

单例模式 确保一个类最多只有一个实例&#xff0c;并提供一个全局访问点。 &#xff08;某个类的对象有且仅有一个&#xff0c;单例的对象充当的是全局变量的角色&#xff0c;为什么在C里面不直接使用全局变量&#xff0c;而是使用单例来代替全局变量&#xff0c;因为如果直接…

07 按键控制 LED

按键简介 按键开关是一种电子开关&#xff0c;属于电子元器件类。常见的按键开关有两种&#xff0c;第一种是轻触式按键开关&#xff08;简称轻触开关&#xff09;&#xff0c;使用时以向开关的操作方向施加压力使内部电路闭合接通&#xff0c;当撤销压力时开关断开&#xff0…

html的表单标签(上):form标签和input标签

表单标签 表单是让用户输入信息的重要途径。 用表单标签来完成与服务器的一次交互&#xff0c;比如你登录QQ账号时的场景。 表单分成两个部分&#xff1a; 表单域&#xff1a;包含表单元素的区域&#xff0c;用form标签来表示。表单控件&#xff1a;输入框&#xff0c;提交按…

48 slab 的实现

前言 这里说的是 内核中分配小对象的一种内存分配方式 slab 呵呵 经典程度不必多说了, 内核使用的大多数数据结构 基本上是基于 slab 进行内存分配的 这里 我们来看一下 slab 如何分配对象 几个分配层级, c->free_list, c->page, c->partial, new_slab 1. 先…

【HarmonyOS】【DevEco ohpm ERROR: NOTFOUND package “@ohos/hypium“如何解决

参考 &#xff1a;&#xff08;无效&#xff09; 华为开发者论坛 DevEco创建项目时的错误解决_6 月 优质更文活动_路北路陈_InfoQ写作社区 解决&#xff1a; HormonyOS-DevEco Studio新建空项目ERROR解决_oh_modules\ohos\hypium-CSDN博客 将 .ohpm文件夹中的hypium文件夹复…

Openharmony - HDF驱动小示例和测试程序

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 1. 创建KHDF示例驱动1.1. 创建KHDF项目1.2. HDF驱动程序实现1.2.1. 驱动入口1.2.2. 实现Dispatch方法1.2.3. 硬件业务初始化与释放1.2…

(每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第10章 项目进度管理(六)

博主2023年11月通过了信息系统项目管理的考试&#xff0c;考试过程中发现考试的内容全部是教材中的内容&#xff0c;非常符合我学习的思路&#xff0c;因此博主想通过该平台把自己学习过程中的经验和教材博主认为重要的知识点分享给大家&#xff0c;希望更多的人能够通过考试&a…

Flink Catalog 解读与同步 Hudi 表元数据的最佳实践

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

python-Scrapy框架入门1111111111111

此网站爬取江南大学官网新闻信息 https://news.jiangnan.edu.cn/yw.htm Scrapy安装 mac | Linux : pip install scrapy windows: pip install wheelpip install pywin32安装Twisted &#xff1a; pip install Twisted_iocpsupport-1.0.2-cp310-cp310-win_amd64.whl (该文件去…

使用Nginx或者Fiddler快速代理调试

1 背景问题 在分析业务系统程序问题时,存在服务系统环境是其它部门或者其它小组搭建或运维的,并且现在微服务时代,服务多且复杂,在个人机器上搭建起如此环境,要么费事费力,要么不具备充足条件。 急需有一种方法或者工具可以快速辅助调试定位分析问题。本文下面介绍代理方…

算法沉淀——多源 BFS(leetcode真题剖析)

算法沉淀——多源 BFS&#xff08;leetcode真题剖析&#xff09; 01.矩阵02.飞地的数量03.地图中的最高点04.地图分析 多源 BFS 是指从多个源点同时进行广度优先搜索的算法。在传统的 BFS 中&#xff0c;我们通常从一个起始点开始&#xff0c;逐层遍历所有的相邻节点。而在多…

IDEA-常用插件

1、Mybatis Log Free 当我们使用mybatis log在控制台输出sql 内容&#xff0c;输出内容将语句与参数分开打印&#xff0c;还需要手动将参数替换到指定位置。 使用对应插件后&#xff0c;自动将输出内容组装成完整的可直接执行的SQL 在插件市场 查看对应名称&#xff0c;并安装。…