【Linux】进程信号详解(一)信号概念信号产生

news2024/10/6 5:59:20

文章目录

  • 前言
  • 信号概念
  • 信号入门
    • 1.查看所有信号
    • 2.信号处理常见方式
    • 3. 发送信号过程
    • 信号是谁发送的?
  • 信号产生
    • 介绍signal函数来捕捉进程
    • 1.通过键盘产生
      • 例子:
      • Core Dump核心转储
    • 2.程序出现异常,导致收到信号
      • 空指针异常
      • 浮点数异常
    • 3. 调用系统函数向进程发信号
      • kill函数
      • raise函数
      • abort函数
    • 软件条件,触发信号发送
      • sigpipe信号
      • sigalarm信号
  • 总结

前言

我们的生活中有很多的信号,例如早上的闹钟,过马路时的红绿灯,还有考试考砸回家之后妈妈的脸色等等都是信号。
例如早上起床时的闹钟,听到闹钟响了之后,我们就知道了我们接下来的动作,就是要起床去敲代码了,但是在听到闹钟之后,可能我们还有点困,把闹钟关掉了,但是闹钟已经响了这件事在我们的脑子里已经留下了印象,等过一会在一个合适的时间起床。
但是这跟我们的进程信号有什么关系呢?
其实他们之间的关系很大,在进程接收到一个信号之前,进程就早已经知道接下来的处理动作,而且在进程收到信号之后,也并不是说马上就去处理这个信号,而是会将这个信号保存下来,在一个合适的时间再去处理它,这与生活中的例子是十分相似的。

信号概念

信号是进程之间事件异步通知的一种方式,属于软中断

接下来通过一个例子来了解一下信号:

#include<stdio.h>
#include<unistd.h>
int main()
{
  while(1)
  {
    printf("i am process,i am waiting a signal!\n");
    sleep(1);
  }
  return 0;
}

在这里插入图片描述
在上边的程序运行之后,屏幕上会每隔一秒钟打印出一串信息,当我们按下Ctrl+c时,他便停止打印了,这其实就是我们通过键盘让操作系统给进程发送了信号,进程接收到信号之后才停止运行。
在这里插入图片描述
通过指令,也可以观察得出,在使用Ctrl+c,本来运行的进程就被杀死了。

信号入门

1.查看所有信号

使用kill -l指令就可以查看所有的信号。
在这里插入图片描述
仔细的同学就会发现,每个信号都有一个编号,但是呢,编号是从1到3134到64,没有32和33号信号,而34号以上的信号是实时信号,我们只讨论前边的普通信号

2.信号处理常见方式

刚才前边我们提到了信号在被发送之后,肯定需要处理,所以信号就有三种处理方式:

1.默认动作
2.忽略动作
3.自定义动作(通过自定义动作,我们可以实现对信号的捕捉)。

3. 发送信号过程

我们根据信号发送的时间,我们将信号发送分为三个过程,

一是信号产生
二是信号保存
三是信号处理

后边的讲解我们就来围绕这三个方面。

信号是谁发送的?

其实信号本质上也是数据,需要保存在进程的PCB中,所以发送信号本质上就是向进程的task_struct中写入数据,但是内核并不相信任何人,所以能写入数据的只有操作系统,所以说信号肯定是由os发送的。

信号产生

介绍signal函数来捕捉进程

signal
头文件:
#include <signal.h>
函数原型:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
第一个参数signum:需要捕捉的信号编号
第二个参数handler:对信号自定义的行为,对捕捉信号的处理方法(函数),handler是一个回调函数,该处理方法的参数是 int,返回值是void
sighandler_t是一个函数指针
在这里插入图片描述

1.通过键盘产生

例子:

根据前边那个例子,我们输入Ctrl+c,可以给进程发送信号,说明信号是可以通过键盘产生的,你们肯定有人好奇这是几号信号呢?为了验证这个问题,我们就可以通过捕捉信号来解决:

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main()
{
  void handler(int signo)
  {
        printf("i am %d signal\n",signo);
  }
  while(1)
  {
     for(int i=1;i<=31;i++)
     {
       signal(i,handler);
     }
    printf("i am process,i am waiting a signal!\n");
    sleep(1);
  }
  return 0;
}

在这里插入图片描述
我们来捕捉1到31号新号,在按下ctrl+c后,发现捕捉到了2号新号。这时当进程跑起来之后,按下ctrl+c后,进程不会被杀死,为了终止进程,可以使用kill -9 指令来终止进程,后边详细介绍。
在这里插入图片描述
同时,按下ctrl+\也可以发送信号终止进程。
在这里插入图片描述
那么2号信号和3号信号都可以终止进程,他们有什么区别呢?
在这里插入图片描述
通过man 7 signal 指令可以查看普通信号的默认动作
在这里插入图片描述
我们发现2号信号的默认动作是Term,3号新号的默认动作是Core,他们之间有什么区别的,Term就是终止进程,而Core是进行核心转储,那么什么是核心转储呢?

Core Dump核心转储

首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部 保存到磁盘上,文件名通常是core,这叫做Core Dump。进程异常终止通常是因为有Bug,比如非法内存访问导致段错误,
事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug(事后调试)。一个进程允许=产生多大的core文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: $ ulimit -c 1024

在linux云服务器上,默认核心转储是关闭的,我们通过ulimit -a可以查看是否打开,使用ulimit -c 1024可以打开核心转储。
在这里插入图片描述
在这里插入图片描述
在核心转储功能打开之后,我们的程序如果出了bug,我们就可以通过gdb调试直接找出程序哪一行出现了问题,下边我们通过例子来验证一下这个功能:

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main()
{
  //野指针错误
  int* p=NULL;
  *p = 100;
  return 0;
  }

在这里插入图片描述
我们发现当我们打开了核心转储功能之后,运行错误之后,会生成core文件,方便我们通过gdb调试来知道到底是哪一行出错了。
在这里插入图片描述
接下来使用gdb进行调试:
第一步:
修改makefile文件
在这里插入图片描述
第二步:
进行gdb调试:
在这里插入图片描述
最终我们发现,通过核心转储功能,我们获得了到底是哪一行出错了。

2.程序出现异常,导致收到信号

空指针异常

上个例子就是一个空指针异常,空指针异常就会造成进程的崩溃。
在这里插入图片描述
在这里插入图片描述
空指针异常会收到的是11号信号,当然也可以通过捕捉信号来验证:

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main()
{
  void handler(int signo)
  {
     printf("i am %d signal\n",signo);
  }
  for(int i=1;i<=31;i++)
  {
      signal(i,handler);
  }
  //野指针错误
  int* p=NULL;
  *p = 100;
  return 0;
}

在这里插入图片描述

浮点数异常

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main()
{
  void handler(int signo)
  {
     printf("i am %d signal\n",signo);
  }
  for(int i=1;i<=31;i++)
  {
     signal(i,handler);
  }
  //浮点数异常
  int a=100;
  a/=0;
  printf("%d",a);
  return 0;
}

在这里插入图片描述
通过信号捕捉,我们发现浮点数错误发送的是8号信号,相同的,我们也可以根据核心转储来调试发现哪一条程序出现了问题。

3. 调用系统函数向进程发信号

kill函数

头文件
#include <sys/types.h>
#include <signal.h>
函数原型:
int kill(pid_t pid, int sig);
参数
第一个参数pid就是进程的pid
第二个参数sig是信号的编号
返回值
发送成功,返回0,否则返回-1
在这里插入图片描述

我们发现kill不仅是一条可以终止进程的指令,也是一个系统调用,这样我们就可以创建一个进程模拟kill指令的行为。

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
  if(argc!=3)
  {
    printf("Usage:\n\t %s signo who\n", argv[0]);
    exit(1);
  }
  pid_t pid =atoi(argv[1]);
  int signo =atoi(argv[2]);
  kill(pid,signo);
  return 0;
}

再实现一个不断循环打印的进程。
在这里插入图片描述
我们使用我们模拟形成的进程后加上命令行参数,就可以实现这个功能。

raise函数

给自己这个进程发信号
在这里插入图片描述

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
int main()
{
  int count=0;
  while(1)
  {
    count++;
    sleep(1);
    printf("this is a process\n");
    if(count>5)  
      raise(2);
  }
  return 0;
}

这段代码就是让进程在五秒后给自己发送一个二号信号来终结自己。
在这里插入图片描述

abort函数

让自己给自己发送指定的信号
在这里插入图片描述
abort就是让进程自己给自己发送6号信号,也是终止进程。
在这里插入图片描述

软件条件,触发信号发送

sigpipe信号

匿名管道使用的时候,我们需要让父子进程一个关闭读端,一个关闭写端,当读端不读并且关闭读端的文件描述符`,写端就会收到一个信号代表读端已经关闭了。写端会收到sigpipe(13)号新号,是一种典型的软件条件。
在这里插入图片描述

sigalarm信号

还有alarm可以设置一个闹钟,后边可以加一个时间,在时间结束之后会发送一个信号。

函数:alarm
头文件:
#include <unistd.h>
函数原型:
unsigned int alarm(unsigned int seconds);
参数:传入一个时间,单位秒
返回值:
若调用alarm函数前,进程已经设置了闹钟,则返回上一个闹钟时间的剩余时间,并且本次闹钟的设置会覆盖上一次闹钟的设置
在这里插入图片描述

总结

今天我们学习了信号的概念和信号的产生的四种方式,后续会讲解信号的后续内容。

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

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

相关文章

1_1torch基础知识

1、torch安装 pytorch cuda版本下载地址&#xff1a;https://download.pytorch.org/whl/torch_stable.html 其中先看官网安装torch需要的cuda版本&#xff0c;之后安装cuda版本&#xff0c;之后采用pip 下载对应的torch的gpu版本whl来进行安装。使用pip安装时如果是conda需要切…

【Linux】安装部署elasticsearch

安装 Java 在安装 Elasticsearch 之前&#xff0c;您需安装并配置好 JDK, 设置好环境变量 $JAVA_HOME。 众所周知&#xff0c;Elasticsearch 版本很多&#xff0c;不同的版本对 Java 的依赖也有所差别: Elasticsearch 5 需要 Java 8 以上版本&#xff1b;Elasticsearch 6.5 开…

旋转目标检测【1】如何设计深度学习模型

前言 平常的目标检测是平行的矩形框&#xff0c;“方方正正”的&#xff1b;但对于一些特殊场景&#xff08;遥感&#xff09;&#xff0c;需要倾斜的框&#xff0c;才能更好贴近物体&#xff0c;旋转目标检测来啦~ 一、如何定义旋转框 常见的水平框参数表达方式为&#xff0…

PMP项目管理-[第九章]资源管理

资源管理知识体系&#xff1a; 规划资源管理&#xff1a; 估算活动资源&#xff1a; 获取资源&#xff1a; 建设团队&#xff1a; 管理团队&#xff1a; 9.1 规划资源管理 定义&#xff1a;定义如何估算、获取、管理和利用团队以及实物资源的过程 作用&#xff1a;根据项目类型…

Azure Data Lake Storage Gen2 简介

Azure Data Lake Storage Gen2 基于 Azure Blob 存储构建&#xff0c;是一套用于大数据分析的功能。 Azure Data Lake Storage Gen1 和 Azure Blob Storage 的功能在 Data Lake Storage Gen2 中组合在一起。例如&#xff0c;Data Lake Storage Gen2 提供规模、文件级安全性和文…

Cesium入门之三:隐藏Cesium初始化页面小部件的两种方法

上一级我们实现了第一个三维地球&#xff0c;但是在这个页面上有很多小部件&#xff0c;我们不想让其显示&#xff0c;应该如何设置呢&#xff1f;这一节我们通过两种方式来隐藏小部件 方法1&#xff1a;通过js代码实现 在js代码中&#xff0c;通过在new Cesium.Viewer(conta…

算法之路--直接插入排序算法

在介绍插入排序算法之前&#xff0c;先举证一个我们都熟悉不过的例子即可理解插入排序。我们在打牌的时候&#xff0c;由于每次抽到的牌大小不一&#xff0c;为了在出牌时了解自己手里都还剩什么牌型&#xff0c;所以每次对抽到的新牌都会做一个排序&#xff0c;怎么比较呢&…

AWS 中的另外一种远程工具 AWS Session Manager

作者&#xff1a;SRE运维博客 博客地址&#xff1a;https://www.cnsre.cn/ 文章地址&#xff1a;https://www.cnsre.cn/posts/230129126154/ 相关话题&#xff1a;https://www.cnsre.cn/tags/aws/ 背景需求 因为项目的安全性。为了避免项目的服务器暴露在公网中。很多时候我们…

设计原则之【迪米特法则】,非礼勿近

文章目录 一、什么是迪米特法则1、理解迪米特法则2、如何理解“高内聚、松耦合”&#xff1f; 二、实例1、实例12、实例2 一、什么是迪米特法则 迪米特原则&#xff08;Law of Demeter LoD&#xff09;是指一个对象应该对其他对象保持最少的了解&#xff0c;又叫最少知道原则&…

支付系统设计三:渠道网关设计01-总览

文章目录 前言一、开发框架二、E-R图三、管理后台配置四、运行时执行流程五、屏蔽渠道差异总结 前言 在《支付系统设计一&#xff1a;支付系统产品化》文章中&#xff0c;我们知道支付渠道网关主要具有以下功能&#xff1a; 统一支付出口&#xff0c;提供丰富的支付工具原子能…

详解:扫雷游戏的实现

扫雷游戏的实现 设置雷排查雷标记雷打印棋盘初始化棋盘获得雷的个数扩展区域test.c的实现meni.c的实现meni.h的实现 铁汁们&#xff0c;今天给大家分享一篇扫雷游戏的实现&#xff0c;来吧&#xff0c;开造⛳️ 1.需要存储雷的信息&#xff0c;创建二维数组来存储数据信息&…

gateway的使用

什么是Spring Cloud Gateway 网关作为流量的入口&#xff0c;常用的功能包括路由转发&#xff0c;权限校验&#xff0c;限流等。 Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架&#xff0c;定位于取代 Netflix Zuul。相比 Zuul 来说&#xff0c;Spring Cloud …

第1章 量化设计与分析基础

1.1 引言 如今一台价格不足500美元的手机&#xff0c;性能便堪比1993年世界上最快的售价5000万美元的计算机&#xff0c;这种快速发展既得益于计算机制造技术的发展&#xff0c;也得益于计算机设计的创新。 纵观计算机发展的历史&#xff0c;技术一直在稳定地提升&#xff0c…

【COT】Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

文章目录 主要解决什么问题采用什么方法实验分析与结果消融实验Commonsense ReasoningSymbolic Reasoning 问题与展望 Chain-of-Thought Prompting Elicits Reasoning in Large Language Models 主要解决什么问题 大语言模型越来越大&#xff0c;效果越来越好。但是在一些具有…

Sui Builder House首尔站|主网上线后首次亮相

Sui Builder House提供与全球Sui构建者会面、合作并学习Sui平台前沿技术的机会。Sui基金会计划将于2023年在全球12个城市举办Sui Builder House。截止目前&#xff0c;已成功在美国丹佛市、越南胡志明市和中国香港举办三场Builder House活动。 Sui Builder House首尔站将于6月…

【D435i深度相机YOLO V5结合实现目标检测】

【D435i深度相机YOLO V5结合实现目标检测】 1. 前言2 分析2.1 关于yolo部分2.2 关于获取三维坐标的部分2.3 关于文件结构部分 3. 代码 1. 前言 参考&#xff1a;Ubutntu下使用realsense d435i&#xff08;三&#xff09;&#xff1a;使用yolo v5测量目标物中心点三维坐标 欢迎大…

满意度指标- NPS 的ABtest(公式推导)

&#x1f449;A 组的NPS如下 &#x1f449;B 组的NPS如下 &#xff08;下标为1&#xff0c;均为A组的样本数据&#xff1b;下标为2&#xff0c;均为B组的样本数据&#xff09; 要验证A\B两组的NPS差异是否显著&#xff0c;可通过假设检验。 一、假设检验前置准备 1. 选择…

FastDFS理论与Java程序的对接(图片,文件上传)

目录 fastdfs概述Java程序对接fastDFSpom配置java启动类注解yaml文件配置controller类service类 fastdfs概述 什么是分布式文件系统&#xff1f; 是指文件系统管理的物理存储资源不一定直接连接在本地节点上&#xff0c;而是通过计算机与节点相连。 通俗来讲&#xff1a; 传统…

【medini analyze 软件介绍】

medini analyze 软件介绍 简介主要功能&#xff08;功能安全范畴&#xff09;1、HARA2、建模3、FMEA & FMEDA4、FTA*这里只是笔者根据汽车功能安全分析经验简单列举了medini analyze的部分功能&#xff0c;完整的功能介绍请参考ANSYS官网* 简介 medini analyze是一款专业的…

怎么把pdf文件压缩到最小?四招快速压缩!

怎么把pdf文件压缩到最小&#xff1f;平常我们要压缩一个文件&#xff0c;一般都知道该如何操作。系统中自带了压缩工具&#xff0c;只需右键点击需要压缩的对象并选择"压缩"选项即可完成操作。然而&#xff0c;很多人也会发现&#xff0c;尽管大部分的文件都可以通过…