Linux——进程信号(上)

news2024/10/7 8:24:18

目录

前文

一,什么是进程信号

二,信号的产生

2.1 通过按键终端产生信号

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

2.3 由软条件产生信号

2.4  硬件异常产生信号

 总结


前文

上文主要讲了一下进程间用管道通信的相关知识,本文主要带领大家深度认识一下进程信号的相关知识,我们主要从三个方面讲解信号产生,信号保存,信号处理

一,什么是进程信号

信号在我们的日常生活中并不少见,如红绿灯, 当我们看到红灯时会知道需要停下来并且会停下来;当闹钟响起时,我们会起床;当快递员和我打电话说快递到楼下时,我们会下去拿快递等等。这些都是典型的信号,因此我们可以得到第一条结论信号其实就是信息加上处理动作。

 

而在这些信号中我们还发现一个特征,就是即使还没有收到信号,我们也都明白这些信号的含义 ,也就是知道怎么处理信号,例如即使红绿灯红灯没亮,我们也知道红灯需要停下来等待。而在进程中也是这样,现实里是老师或者家长教会我们如何处理信号,而在进程中是我们程序员教会我们的进程如何处理信号

另外,在我们的日常生活中,信号可能随时产生, 例如快递,我们不知道快递具体的送到时间,假如快递送到的时候,我们在打LOL激情排位,马上就要把对方家推掉了,此时我们可能会让快递员在下面等俩分钟,我们打完再下去拿。此时就形成了信号产生————信号保存————信号处理,在原先的信号产生和信号处理中间多了个信号保存,即使我们不能立即处理这个信号,也需要把他保存起来,留到后面处理。因此,信号的产生对于进程来讲是异步的,也就是进程并不清楚信号什么时候传递进来,因此在接收到信号之前都在忙自己的事,不会什么也不做就等着信号的传递。

 那么信号在进程中是怎么保存的呢?又是记录在哪里的呢?

首先我们来看看linux中的常用信号

 如上图所示,每个信号都由一个编号和一个宏定义名称组成,以红线为界限,前31个信号是常规信号是我们这节课要学习的重点,后面的是实时信号我们目前不学习。

因此我们需要保存的信号就是前31个,那么有什么办法呢?这里我们只需要确认是否接受到信号,也就是信号有无的问题,因此我们可以用0表示没有,1表示有 ,恰好信号为31个,因此我们可以用位图的数据结构来表示,也就是用一个32位整形的每一个二进制位映射一个信号,如第一个比特位映射信号1

 

 那么这数据是在哪里保存的呢?

在linux中,每一个进程,操作系统都会创建一个task_struct结构体保存其相关信息,因此上面的signal就保存在进程对应的task_struct中

struct task_struct
{
    ...
    uint_32 signal;
    ...
};

 因此我们可以得知,所谓的发信号其实就是写入信号,直接修改进程的信号位图中映射的比特位,而task_struct结构由操作系统直接维护,只能由操作系统修改,因此后面无论信号如何产生,最后都有操作系统完成发送

讲完信号保存我们来稍微认识一下信号处理,信号处理主要有以下三种方式

1.默认动作,例如红灯停,绿灯行

2.忽略信号,如红灯亮的时候你不停下来,继续走

3.用户自定义动作,如红灯的时候别人都是停下来,你就比较牛逼了,你直接来一段街舞

到此,信号的基本认识就结束了,接下来我们主要讲一下信号的产生

二,信号的产生

2.1 通过按键终端产生信号

什么是按键终端呢?其实就是用键盘输入信号,例如常见的Ctrl+c,Ctrl+\

 

如上图所示, 用户按下Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程,前台进程因为收到信号,进而引起进程退出(主要只有前台进程才可以收到信号)

Ctrl+c,Ctrl+\分别对应信号2 SIGINT以及信号3 SIGQUIT.

SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump(当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部 保存到磁盘上,文件名通常是core,这叫做Core Dump。)。

那么如何证明Ctrl+c,Ctrl+\分别对应信号2 SIGINT以及信号3 SIGQUIT呢?

这时我们可以用signal函数

 

 如上图所示,handler是一个函数指针,signum为对应信号,而signal可以将接受到的signum信号的处理方式改成handler(handler函数的格式需要和上面typedef定义的格式对应)。而我们的证明方式就是将2,3号信号的处理方式改成handler从而验证Ctrl+c,Ctrl+\分别对应信号2 SIGINT以及信号3 SIGQUIT.

 

 如上图所示,我们发现Ctrl+c,Ctrl+\分别对应信号2 SIGINT以及信号3 SIGQUIT.

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

在linux中我们指令发送信号通常是用kill命名完成,而kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定的信号(自己给自己发信号)。

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1。

 kill第一个参数的pid指的是目标进程的pid,signo为要发送的信号,rasie的signo参数也是要发送的对象,但是目标为自己。接下来我们简单运用一下

 目标进程如下所示

int main()
{

    /* signal(2,myhandler);
    signal(3,myhandler); */

    while(true)
    {
        cout<<"我是进程,我的pid: "<<getpid()<<endl;
        sleep(1);

    }
    
    return 0;
}

 kill进程

int main(int argc, char *argv[])
{
    int signal=atoi(argv[1]);
    int traget_id=atoi(argv[2]);
    int ret1=kill(traget_id,signal);//指令参数读取指令
    assert(ret1==0);
    
    while(true)
    {
        cout<<"我是进程,我的pid: "<<getpid()<<endl;
        sleep(10);
        int ret2=raise(9);
        assert(ret2==0);

    }
    

    return 0;
}

实验结果

 

 如图,kill用kill函数用信号9杀死了进程8196,然后10s后调用raise用信号9杀死自己

此外除了kill和raise接口还有一个abort接口 ,abort接口会使当前进程接受到信号而异常终止

#include <stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值

2.3 由软条件产生信号

进程在运行过程中不符合某种软件条件时OS会向进程发送信号,例如管道的读端关闭,写端依旧在向管道中写入内容,当写端将管道写满之后,OS会向写端进程发送SIGPIPE信号(13),进程对于SIGPIPE信号的默认处理方式是Term(终止进程)。而本节主要介绍alarm函数 和SIGALRM信号。

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。打个比方,某人要小睡一觉,设定闹钟为30分钟之后响,20分钟后被人吵醒了,还想多睡一会儿,于是重新设定闹钟为15分钟之后响,“以前设定的闹钟时间还余下的时间”就是10分钟。如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数,我们来个小项目验证一下

void myhandler(int signal)
{
    cout<<"我的信号是: "<<signal<<endl;
    int n=alarm(10);
    cout<<"闹钟剩余时间: "<<n<<endl;

}

int main()
{
    cout<<"我是进程,我的pid: "<<getpid()<<endl;
    signal(2,myhandler);
    // signal(3,myhandler);
    alarm(10);//十秒后必停止
    while(true)
    {
        sleep(1);
    }
    
    return 0;
}

如上图,我们先将信号2的处理方式替换成myhandler,然后我们闹钟倒数十秒,十秒后自动响起进程结束,而在此之间当我们发送信号2时,会自动调用myhandler中的alarm,此时再次发送信号2,就可以验证alarm返回值的问题了

 

 结果如上所示,当我们发送信号2时,myhandler会调用alarm,当我们在myhandler中的alarm响之前再次发送信号2,我们发现alarm的返回值为上一次闹钟时间的剩余时间。

2.4  硬件异常产生信号

硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号

 以我们常见的除0错误为例,当我们除0进程在运行时,数据会加载到cpu计算,然后除0会导致结果溢出,此时cpu的溢出检测码会从0置为1,此时操作系统作为硬件软件的管理者,会检测到cpu的异常码,然后通过cpu找的异常码所在的进程,并向该进程发送SIGFPE码中断该进程.

 接下来我们就用signal函数验证一下,SIGFPE对应的信号为8

 运行结果如下

如图,首先经过实验我们发现除0所发送的异常信号确实是8号信号(SIGFPE),其次我们并没有写循环也只有一行除0但是操作系统却一直给我们发送8号信号,这又是因为什么呢?这是因为进程一直没有关闭,因此CPU中的溢出检测码就一直为1,操作系统就会一直检测到,就导致操作系统会不停的给进程发送信号。

 

另外我们还有一个发现,就是在编译时编译器会有除0警告,但是依旧可以编译通过,这是因为除0是在进程运行中硬件检测出来的,不属于语言层问题,属于硬件层,因此编译器会警告但仍然能够编译通过。

 总结

本文主要带领大家先浅显的认识一下信号发出,信号保存,信号处理,并且带领大家深入了解信号发出的四种方式,而信号保存和信号处理会在后续放出。

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

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

相关文章

cpolar在windows系统下的关闭方法

计算机&#xff0c;右键-管理 管理–服务–cpolar service&#xff0c;停止服务

InfluxDB 压力测试

一、基础环境 1. InfluxDB V1.7.8&#xff0c;预置了10.3G 数据做为初始数据 &#xff08;调整了 部分参数&#xff0c;否则数据库动不动就崩溃&#xff09; 2. 模拟141个设备&#xff0c;共计1390个点位 3. 服务器配置 128G内存&#xff0c;2.4Ghz CPU&#xff0c;虚拟机 …

前端十万个为什么——软件设计的架构模式

&#x1f600;博主&#xff1a;小猫娃来啦 &#x1f600;文章核心&#xff1a;软件设计的架构模式 上篇文章&#xff0c;我们聊了一下前端的普遍性问题以及解决策略。书接上文&#xff0c;我们今天聊聊软件设计的架构模式。 在正文开始前&#xff0c;先思考几秒&#xff1a;为…

《安全软件开发框架(SSDF) 1.1:降低软件漏洞风险的建议》解读(二)

安全软件开发框架SSDF是由美国国家标准与技术研究院发布的关于安全软件开发的一组实践&#xff0c;帮助开发组织减少发布的软件中的漏洞数量&#xff0c;减少利用未检测到或未解决的漏洞的潜在影响&#xff0c;从根本上解决漏洞防止再次发生。本文根据《Secure Software Develo…

想学会如何翻译pdf中的英文?让我教你三招

曾经有一个名叫小明的年轻人&#xff0c;他是一名热爱阅读的书虫。每天&#xff0c;他都会沉浸在大量的pdf文档中&#xff0c;探索着各种知识的海洋。然而&#xff0c;有时候他遇到了一些困扰&#xff0c;因为有些pdf文档并不是他熟悉的语言书写的。小明很苦恼&#xff0c;他希…

python接口自动化(十四)--session关联接口(详解)

简介 上一篇cookie绕过验证码模拟登录博客园&#xff0c;但这只是第一步&#xff0c;一般登录后&#xff0c;还会有其它的操作&#xff0c;如发帖&#xff0c;评论等等&#xff0c;这时候如何保持会话呢&#xff1f;这里我以jenkins平台为例&#xff0c;给小伙伴们在沙场演练一…

vue3在浏览器段展示海康监控视频

一、需求 需要在浏览器点击查看海康的监控视频 二、最后成果展示 插件下载地址&#xff1a;https://download.csdn.net/download/xm_w_xm/87995593 三、思路和方法 3.1 首先安装插件&#xff0c;可以在上面的地址中下载安装&#xff0c;建立一个dom <div id"playW…

利用Dockerfile构建带sshd、jdk服务的自定义镜像

什么是Dockerfile? Dockerfile 是一个文本格式的配置文件&#xff0c; 用户可以使用 Dockerfile 来快速创建自定义的镜像 dockerfile 的基本结构 Dockerfile 由一行行命令语句组成&#xff0c;并且支持以 # 开头的注释行。 一般的&#xff0c;Dockerfile 分为四部分&#…

SpringCloud入门实战(十一)-Spring Cloud Stream消息驱动概述

&#x1f4dd; 学技术、更要掌握学习的方法&#xff0c;一起学习&#xff0c;让进步发生 &#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我&#xff0c;不迷路 。 &#x1f490;学习建议&#xff1a;1、养成习惯&#xff0c;学习java的任何一个技术…

聚焦云原生安全攻防|构建纵深防御的运行时威胁检测体系

7月2日&#xff0c;诸子云北京分会研讨会活动—网络安全攻防对抗在北京成功举办。 作为国内云原生安全领导厂商&#xff0c;安全狗也参与此次活动。 厦门服云信息科技有限公司&#xff08;品牌名&#xff1a;安全狗&#xff09;成立于2013年&#xff0c;致力于提供云安全、&…

Scenario Runner (CARLA)

1. How to run scenarios —Type 2. How to run scenarios —Functionalities

系统提权与数据窃取

系统提权与数据窃取 一、后渗透二、后渗透的技术2.1、提权2.2、横向移动2.3、持久化2.4、数据窃取2.5、漏洞利用 三、meterpreter后渗透3.1、靶机权限提升3.1.1、windows内核/服务漏洞3.1.2、bypassUAC3.1.2.1、bypassuac 进程注入3.1.2.2、bypassuac_injection 内存注入3.1.2.…

Android Studio实现内容丰富的安卓医院医生招聘平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号120 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查…

软件设计师(九)数据库技术基础

数据库技术是研究数据库的结构、存储、设计、管理和应用的一门软件学科 一、基本概念 1、数据库和数据库系统 数据库系统&#xff08;DataBase System&#xff0c;DBS&#xff09;是一个采用了数据库技术&#xff0c;有组织地、动态地存储大量数据&#xff0c;方便多用户访问…

公众号授权登录h5

公众号授权登录h5 . 前几天一个月薪35k的兄弟&#xff0c;给我推了一个人工智能学习网站&#xff0c;看了一段时间挺有意思的。包括语音识别、机器翻译等从基础到实战都有&#xff0c;很详细&#xff0c;分享给大家。大家及时保存&#xff0c;说不定啥时候就没了。 . 步骤 …

认识JavaScript

大家好,今天我们来认识一下JavaScript相关内容 目录 &#x1f437;1.JavaScript是什么&#x1f437;2.JavaScript发展史&#x1f437;3.JavaScript 和 HTML 和 CSS 之间的关系&#x1f437;4.JavaScript 运行过程&#x1f437;5.JavaScript 的组成&#x1f437;6.用JavaScript写…

JavaScript 实现一键复制(id,账号)

文章目录 HTML准备JavaScript 逻辑css 在前端有很多的时候需要一键复制账号&#xff0c;密码等&#xff0c;比如QQ的复制QQ账号&#xff0c;一些程序应用的个人信息页&#xff0c;都会有一键复制这个功能&#xff0c;下面给大家分享一下一键复制的实现方法 HTML准备 先提前准备…

【Linux修炼】开发工具使用

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

计算机丢失msvcr110.dll是什么意思?那个修复方法更简单

Windows系统的电脑运行一段时间&#xff0c;总是不可避免出现一些系统报错&#xff0c;比如在运行游戏或游戏的时候&#xff0c;报错提示“计算机丢失msvcr110.dll”&#xff0c;“找不到msvcr110.dll”是什么意思呢&#xff1f;我是运行photoshop的时候报错的&#xff0c;场景…