_Linux进程信号详解

63b40ec1-ea08-eb11-8da9-e4434bdf6706.png

信号是什么

一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件

信号是多种多样的,并且一个信号对应一个事件,这样才能做到收到一个信号后,知道到底是一个什么事件,应该如何处理(但是要保证必须识别这个信号)

信号的种类

使用kill-l命令查看信号种类

68b40ec1-ea08-eb11-8da9-e4434bdf6706.png

一共62种,其中1~31是非可靠信号,34~64是可靠信号(非可靠信号是早期Unix系统中的信号,后来又添加了可靠信号方便用户自定义信号,这二者之间具体的区别在下文中会提到)

信号的生命周期

产生》》进程中的注册》》进程中的注销》》捕获处理

信号的产生

硬件事件举例:

  • 如果一个进程试图除以0,那么内核就发送给它一个SIGFPE信号(序号8)
  • 如果一个进程执行一条非法指令,那么内核就发送给它一个SIGILL信号(序号4)
  • 如果进程进行非法存储器引用(野指针、段错误),内核就发送给它一个SIGSEGV信号(序号11)

软件事件举例:

  • ctrl+c 中断信号——20) SIGTSTP
  • ctrl+| 退出信号——3) SIGQUIT
  • ctrl+z 停止信号——2) SIGINT
  • kill命令:kill -signum pid
    当kill命令不带-signum参数时(kill pid),默认的信号是15) SIGTERM
    kill -9 pid则是一个强大的“强杀”命令,能杀死kill pid杀不掉的处于T状态的进程
  • int kill(pid_t pid, int sig);
    kill命令的系统调用接口(在代码中使用kill)
#include 

示例:

#include 

运行结果:

ubuntu@VM-0-7-ubuntu:/home/zeno/c_practice$ ./217_kill
Quit (core dumped)
  • int raise(int signum);
    raise是一个库函数(#include <signal.h>),作用是发送信号到调用这个函数的进程/线程
    在单线程程序中,它等效于kill(getpid(), sig);(也就和上面的示例一样)
    在多线程程序中,它等效于pthread_kill(pthread_self(), sig);
  • void abort();
    abort是一个库函数(#include <stdlib.h>),作用是造成进程异常中止
    在进程中调用abort()就相当于调用了raise(3)
  • unsigned int alarm(unsigned int seconds);
    alarm是一个系统调用接口(#include <unistd.h>),在seconds秒后会将SIGALRM信号传递到调用进程

信号的注册

在pcb中有一个未决(pending)信号集合(未决(pending)的意思是信号产生了但还没有决定怎么做),信号的注册就是指在这个pending集合中标记对应信号数值的二进制位为1

上面的话有些难以理解,我们先来看看在linux内核源码里一个进程的信号是如何保存的

在linux内核源码sched.h中的task_struct结构体里有这样一段关于信号的内容:

/* signal handlers */

上面最后一行的sigpending结构体定义在signal.h中:

struct 

这里的signal就是用来做信号标记的,给一个进程发送一个信号说白了就是在signal里标记一下这个信号曾经来过

那么signal是如何进行标记的呢?还得继续了解一下sigset_t这个结构体

在bits/sigset.h中进行了以下定义:

/* A `sigset_t' has a bit for each signal.  */

注:这里的__sigset_t其实就是sigset_t,只是一个类型名的重定义

在这个结构体中只有一个数组成员,这个数组里存放着一些数作为位图,位图的每一个二进制位就代表了一种信号,0表示未曾收到这个信号,1表示已经收到这个信号

这里需要注意的是,真正存放信号的是数组中某个数的某个二进制位,数组的存在只是因为单独一个数的二进制位存不下这么多种类的信号

现在我们就可以理解,当使用上述方式对某一个进程发送一个信号时,操作系统就会将该进程对应的pending集合中表示相应信号的位图的二进制位由0改为1

但是非可靠信号和可靠信号的注册还有一点区别

为了理解这种区别我们还应该了解一下list_head链表和signal.h中的sigqueue结构体

list_head是linux内核提供的一个用来创建双向循环链表的结构,由于这个结构是没有数据域的所以较为复杂,在这里不做深究,有兴趣可以通过这篇博客详细了解

我们需要知道的是,内核通过一个以list为表头的链表将所有产生的信号都串在了一起,链表中的每个节点的结构是一个sigqueue:

/*

这个结构体保存信号所携带的信息

现在我们就可以对非可靠信号和可靠信号的区别有一定的了解了

  • 1~31非可靠信号的注册:
    当试图对一个进程发送一个非可靠信号时,若发现位图上对应的位为0,则置为1,并在list_head链表里加入一个sigqueue节点;若发现位图上对应的位已经为1,则直接返回。简单地说就是若信号还未注册,则注册一下,若已经注册,则什么都不做
  • 34~64可靠信号的注册:
    当试图对一个进程发送一个可靠信号时,若发现位图上对应的位为0,则置为1,并在list_head链表里加入一个sigqueue节点;若发现位图上对应的位已经为1,对该位不进行操作但依旧在链表里加入一个节点。也就是说,每次对进程发送一个可靠信号时,不管该进程之前是否收到过相同的信号,总是会在list_head链表里加入sigqueue节点

对于信号来说,位图只是用来标记有没有待处理信号的,而节点才是信号真正注册的信息

信号的注销

看上文中信号的生命周期会发现,在处理信号之前,会先销毁信号的信息

信号注销存在的目的就是为了抹除信号存在的痕迹,防止对同一个信号进行多次处理

删除要处理的信号sigqueue节点:

  • 若信号是非可靠信号,则直接将位图置0(非可靠信号在没有处理之前只会注册一次)
  • 若信号是可靠信号,则删除后需要判断是否还有相同节点,没有的话才会重置位图为0

信号的捕获处理

在学习信号的捕获和处理之前我们还需要了解一下信号的阻塞

信号的阻塞

信号的阻塞就是阻止一个信号的抵达,当一种信号被阻塞时,它仍可以被发送,但是产生的待处理信号不会被接收,直到进程取消对这种信号的阻塞

在pcb中,有一个阻塞信号集合(blocked位图,实现方式与pending相同),凡是添加到这个集合中的信号,都表示需要阻塞,暂时不处理

那么该如何实现对一个进程的某个信号进行阻塞呢?

我们可以通过sigprocmask函数显式地阻塞和取消阻塞选择的信号:

#include 

参数中的how表示了当前要对blocked集合进行的操作,它的值可从下面三个宏定义中选择一个填入:

  • SIG_BLOCK:添加set中的信号到blocked中(blocked = blocked | set)
  • SIG_UNBLOCK:从blocked中删除set中的信号(blocked = blocked & ~set)
  • SIG_SETMASK:blocked = set

在这个函数中,如果oldset非空,blocked位图以前的值会保存在oldset中

捕获信号与处理信号

接着我们就可以来研究一下捕获信号

当内核准备将控制传递给一个进程时,它会检查该进程的未被阻塞的待处理信号的集合,也就是存在于pending集合中同时又不存在于blocked集合中(pending & ~blocked),如果这个集合为空(通常情况下),那么内核将控制传递到该进程中的下一条指令里

然而,如果该集合是非空的,那么内核会选择集合中的某个信号(通常是序号最小的信号),并且强制该进程接收该信号,收到这个信号会触发进程的某种行为。一旦进程完成了这个行为,那么控制就传递回该进程中的下一条指令

这里的“行为”,就是进程对信号的处理

处理的实现是调用一个信号处理函数signal:

#include 

这里的sighandler_t是一个函数指针类型,signal函数的第一个参数就是信号的序号,我们就可以通过第二个参数来改变处理信号signum的方式:

  • 如果handler是SIG_IGN,那么忽略类型为signum的信号
  • 如果handler是SIG_DFL,那么类型为signum的信号行为恢复为默认行为
  • 在其它情况下,handler是一个用户定义的函数的地址,也就是指向一个信号处理程序的函数指针,只要进程收到一个类型为signum的信号,就会调用这个函数

需要注意的是,在所有信号中,有两个信号不可被阻塞,不可被自定义修改处理方式,也不可被忽略,这两个信号分别是9) SIGKILL19) SIGSTOP

一般情况下对于信号的捕获和处理都是一起被提到的,上文中对“捕获”和“处理”的分界可能并不是特别准确,在《深入理解计算机系统》中对捕获信号和处理信号的定义如下:

调用信号处理程序称为捕获信号,执行信号处理程序称为处理信号

现在我们通过一个具体的例子来感受一下信号的阻塞与接触阻塞的操作和信号的捕获处理以及可靠信号与非可靠信号的区别:

#include 

运行程序并分别通过ctrl+c和kill命令多次发送2号和40号信号:

zeno@VM-0-7-ubuntu:~$ ./mask
presse enter to continue:
^C^C^C^C^C^C^C^C^C^C
zeno@VM-0-7-ubuntu:~$ ps -ef | grep mask | grep -v grep
zeno     29043 27880  0 14:09 pts/10   00:00:00 ./mask
zeno@VM-0-7-ubuntu:~$ kill -40 29043
zeno@VM-0-7-ubuntu:~$ kill -40 29043
zeno@VM-0-7-ubuntu:~$ kill -40 29043
zeno@VM-0-7-ubuntu:~$ kill -40 29043

可以看到对于该进程,不论是非可靠信号(2)还是可靠信号(40),都被阻塞导致无法处理,但是接下来按下回车,所有阻塞都会被解除:

zeno@VM-0-7-ubuntu:~$ ./mask 
presse enter to continue:
^C^C^C^C^C^C^C^C^C^C
receive a signal:40
receive a signal:40
receive a signal:40
receive a signal:40
receive a signal:2

在这里我们就可以发现,虽然信号2和信号40都曾发送多次,但是只有信号40也就是可靠信号被处理了多次,而信号2也就是可靠信号只调用了一次信号处理函数,这也就印证了我们上文中所提到的可靠信号与非可靠信号的区别

至此我们就已经大致了解了什么是进程信号和信号的工作过程

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

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

相关文章

java乘法表_Java中四种9*9乘法表的实现方式(附代码)

前言: 初学java,实现99乘法表是必学必会的内容。需求 : 分别写出上下左右,对应四个角的乘法表。思路: 可以先打印出*星星,形成一个直角三角形,然后再替换成乘法公式。代码如下:public class Demo {public static void main(String[] args) {for (int i 1; i <5 ; i) {for (…

excel表格不够怎么添加_Excel表格水印,你以前好象添加错了!

为excel表格添加水印&#xff0c;通常是使用插入-艺术字来完成。但这样做有一个很大的问题&#xff1a;如果表格有很多页&#xff0c;就需要添加N多个艺术字&#xff0c;太麻烦了。其实有一个超简单的批量设置方法&#xff0c;再多页也可以一次性设置。需要添加水印的Excel表格…

电脑手机wifi互传文件_安卓手机文件互传

怎么不借用第三方工具&#xff0c;安卓手机实现相互文件快传呢&#xff1f;苹果&#xff1a;首先不用多说&#xff0c;苹果可以使用Air Drop功能&#xff0c;苹果全家桶可以无障碍互传。长期以来&#xff0c;除开微信和QQ&#xff0c;不同品牌安卓手机互传文件依靠的途径只有蓝…

传统的线性降维方法效果不佳。_10分钟数据降维入门

1. 前言在硕士期间学习研究了数据降维相关的知识&#xff0c;阅读了一些相关文章&#xff0c;也断断续续在知乎上写了一些数据降维的入门级文章&#xff0c;收获了一些小伙伴的赞同&#xff0c;并在GitHub上开源了一些特征抽取算法的源代码&#xff0c;获得了的1.1kstar。因为在…

嵌入式开发网络配置——windows连热点,开发板和电脑网线直连

目录 电脑 WiFi 上网&#xff0c;开发板和电脑直连 使用场景 设置VMware虚拟机的网络配置 Ubuntu设置——版本18.04 ​编辑 windows设置 开发板设置 原因&#xff1a;虚拟机Linux移植可执行程序到开发板失败 最后发现虚拟机的Linuxping不通开发板 下面是我的解决方法 …

java ajax data_jquery ajax 方法中传递的data参数,如何在java类中获取

展开全部var params"username""1";$.ajax({type : "POST", //数据发送方式url : "../servlet/clearCache",dataType : "json", //接受数据格式 (这里有很多,常用的有html,xml,js,json)data:params,//datenew Date(), 要传递…

python环境变量配置_Python的安装、认识、配置环境变量以及helloworld打印的两种方式

Python的安装、认识、配置环境变量以及helloworld打印的两种方式 一、 安装和配置环境变量 首先我们去到Python的官方下载地址根据自己的电脑机型来下载最新的python安装包&#xff0c;网址是https://www.python.org/downloads/ 。 或者点击这里跳转 。 下载之后可以去https://…

java 报表程序_java 报表

http://www.codeceo.com/article/8-java-graph.html前段时间我们为大家分享过一些最常用的Java图表应用和Android图表应用&#xff0c;无论是在PC平台上还是移动平台上&#xff0c;图表和报表功能都是不可或缺的。本文推荐了8款最精彩实用的Java图表应用&#xff0c;大部分图表…

excel跨多个表格求和_看完财务同事用Excel函数完成的进销存报表,老板惊呆了...

有仓库、有商品的地方都离不开进销存软件&#xff0c;有花钱买的、也有花大力气自已找人订制的。网上下载破解版&#xff1f;真的不可靠&#xff0c;万一出现什么问题&#xff0c;你们公司将面临信息损坏或丢失的风险&#xff01;其实&#xff0c;如果只是小规模的库存商品管理…

苹果自带相册打马赛克_如果你用苹果手机!学会这3个技巧,就能让手机变得更加好用...

如果你用苹果手机&#xff01;这3个技巧一定要学会&#xff0c;能让手机变得更好用现在手机中的黑科技功能越来越多&#xff0c;就拿iPhone手机来说&#xff0c;很多朋友选择这款手机不仅是因为拥有非常流畅的系统&#xff0c;手机中自带的黑科技功能也是大家选择它的原因。今天…

给与 x 距离不超过 d 的点权值 a_一年级不上网课,妈妈陪孩子一起来完成三单元各课练习及单元卷吧...

部编一年级下册第5课小公鸡和小鸭子课后练习题一、将下列字的音节补充完整。k____ x____ zh____ 块 行 捉 二、选择加点字的正确读音&#xff0c;画“√”。忽然(rn rnɡ)  大喊(hǎn hǎnɡ)上身(shēn sēn)  死去(sǐ shǐ)三、看拼音&#xff0c;写字词。1小明说(&am…

java games_Java Me Games

在GWT的文档里说&#xff0c;大致上CSS的命名规则是这样的"[project]-[widget]&#xff0c;比如gwt-Button&#xff0c;你可以在CSS里定义如下&#xff1a;.gwt-Button{font-size:150%;}但是这样的说明是不充分的&#xff0c;所以这里有必要把他真正的样式表来列一下&…

java timestamp 转换_Java:String和Date、Timestamp之间的转换

一、String与Date(java.util.Date)互转1.1 String -> DateJava代码 String dateStr "2010/05/04 12:34:23";Date date new Date();//注意format的格式要与日期String的格式相匹配DateFormat sdf new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");try {…

bugku 杂项 就五层你能解开吗_9.65米解放龙V杂项危险废物厢式运输车62

亲爱的,点击上方蓝字关注我吧9类危险废物厢式运输车解放龙V2.0半高顶半浮驾驶室底盘参数&#xff1a;龙V2.0半高顶半浮驾驶室、锡柴225马力&#xff0c;6.6排量&#xff0c;164千瓦&#xff0c;百公里耗油30.3L、陕齿8JS85E、435升级冲焊桥(速比4.444)、275/80R22.5-18PR层级、…

python矩阵运算与线形代数_[译] 线性代数:矩阵基本运算

线性代数&#xff1a;矩阵基本运算在本文中&#xff0c;我们将介绍矩阵的大部分基本运算&#xff0c;依次是矩阵的加减法、矩阵的标量乘法、矩阵与矩阵的乘法、求转置矩阵&#xff0c;以及深入了解矩阵的行列式运算。本文将不会涉及逆矩阵、矩阵的秩等概念&#xff0c;将来再探…

torch tensor去掉1维_南昌清污机新价格表1_海腾水工

南昌清污机新价格表1,应用中&#xff0c;应停止机械零件&#xff0c;停止防锈处理&#xff0c;定期在停水面涂抹黄油&#xff0c;开关发生某些异常&#xff0c;立即暂停&#xff0c;及时检查。 开闭时&#xff0c;请注意活塞的上下限位置&#xff0c;以免挡板和卷扬机损坏。 起…

fx系列微型可编程控制器 通信_电气人,三菱Q系列和FX PLC系列之间的区别你都知道吗?...

三菱Q系列和FX系列作为三菱旗下的两大PLC系列&#xff0c;在日常的作业中小伙伴们都会接触到&#xff0c;因此本文将三菱可编程控制器中使用的内置的输入输出继电器、辅助继电器、状态、计数器、数据寄存器等各种软元件的作用和功能进行了说明。Q系列FX系列输入继电器 X输入继电…

left join 效率_人力资源HR的人才测评工具,极大提高招聘效率

作为一个HR小白&#xff0c;打交道最多的就是简历&#xff0c;领导谈的最多的就是提高工作效率&#xff0c;其实这个概念对于我来说还是挺抽象的&#xff0c;经过向前辈的取经&#xff0c;人力资源如何提高效率&#xff0c;做了个小小的总结。首先我们要明白我们的难点有哪些&a…

windows media player 9_openmeetings(开源视频会议系统)的详细安装步骤 (windows版)

一、开源视频会议系统openmeetings的简介&#xff1a;OpenMeetings是一个多语言可定制的视频会议和协作系统。它支持音频、视频&#xff0c;能让你查看每个与会者的桌面。OpenMeetings还包含一个白板&#xff0c;通过白板可以导入各种格式的图片和涂鸦。它是基于OpenLaszlo’s的…

Java实例化后自动执行_Java的实例化顺序(程序执行顺序)

加载/执行顺序&#xff1a;牢记一点&#xff1a;静态和非静态分开处理使用到静态加载时&#xff0c;静态又分为&#xff1a; 静态变量&#xff0c; 静态代码块&#xff0c; 其中加载顺序是按照类中书写的先后顺序加载的非静态加载顺序&#xff1a; 按照非静态书写顺序加载/执行…