Linux进程信号(一)

news2024/11/30 8:46:18

信号产生

  • 1.信号基础知识
  • 2.初步认识信号
  • 3.signal函数
  • 4.技术应用角度的信号
  • 5.调用系统函数向进程发信号
  • 6.由软件条件产生的信号
  • 7.硬件异常产生信号
  • 8.core

🌟🌟hello,各位读者大大们你们好呀🌟🌟
🚀🚀系列专栏:【Linux的学习】
📝📝本篇内容:信号基础知识;初步认识信号;signal函数;技术应用角度的信号;调用系统函数向进程发信号;由软件条件产生的信号;硬件异常产生信号;core
⬆⬆⬆⬆上一篇: 进程间通信
💖💖作者简介:轩情吖,请多多指教(>> •̀֊•́ ) ̖́-

1.信号基础知识

1.信号没有产生,进程也知道该怎么处理它
2.进程在没有收到信号的时候,它就已经能够认识并处理一个信号。程序员设计进程的时候,早就设计了对信号的识别能力
3.信号可能随时产生,所以在信号产生前,进程可能在做优先级更高的事情,可能不能立马处理这个信号,只能在后续合适的时候处理,因此进程收到信号时,需要进程具有记录信号的能力,保存起来
4.信号的产生对于进程来说是异步的(信号产生归产生,进程执行自己的代码)
5.1-31:普通信号 34-64:实时信号
在这里插入图片描述
6.进程的task_struct内部必定存在一个位图结构,用int表示;uint32_t signals;比特位的位置是信号的编号;比特位的内容是指是否收到该信号(0,1)
7.所谓的发送信号,本质其实是写入信号,直接修改特定进程的信号位图中的特定比特位,0->1
8.信号产生之后,不是立即处理,而是在合适的时候
9.处理信号的方式:①默认动作 ②忽略信号 ③ 用户自定义动作

2.初步认识信号

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;
int main()
{
    while (1)
    {
        cout << "我是一个进程,我在执行。。。" << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

一般执行的进程都是前台进程,不执行时bash为前台进程,因此执行时输入指令无法识别。当执行进程时后面加一个&,为后台进程
在这里插入图片描述
但此时要想要退出这个进程只能使用kill -9来杀掉,用别的比如ctrl^c都不行
在这里插入图片描述
其实不管用kill -9还是ctrl^c都是向进程发送了信号,kill -9发送的是9号信号,而ctrl+c是2号信号

3.signal函数

在这里插入图片描述
signal函数可以用来对指定的信号设定自定义处理动作,它的第二个参数就是把对应的处理动作传过去,它的第一个参数是对应要处理的信号,来看下面的例子,我们自定义一下2号信号的处理方式

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;
void handle(int signo)
{
cout<<"我是对应的"<<signo<<"信号"<<endl;
}
int main()
{
	cout<<"pid:"<<getpid()<<endl;
    signal(2,handle);
    while (1)
    {
        cout << "我是一个进程,我在执行。。。" << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
可以发现我们使用kill -2时,它对应的处理方法是我们所自定义的,其实2号信号就是ctrl+c,我们的2
号信号的默认处理动作是终止进程

①signal(2,handle)调用这个函数的时候,handle方法并没有被调用,只是更改了2号信号的处理动作,handle方法只有在2号信号产生的时候才被调用
②默认我们对2号信号的处理动作:终止进程,我们用signal函数,我们在执行用户自定义动作的捕捉
③handle的int参数是特定信号被发送给当前进程的时候,执行handle方法的时候,自动填充对应的信号编号

我们甚至可以给所有的信号设置同一个处理函数,但9号信号不受影响

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;
void handle(int signo)
{
cout<<"我是对应的"<<signo<<"信号"<<endl;
}
int main()
{
    cout<<"pid:"<<getpid()<<endl;
    for(int i=1;i<=31;i++)
    {
    signal(i,handle);
    }
    while (1)
    {
        cout << "我是一个进程,我在执行。。。" << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述

4.技术应用角度的信号

用户输入命令,在shell下启动一个前台进程。用户按下ctrl+c,这个键盘输入产生一个硬件中断,被OS获取。解释成信号,发送给目标前台进程。前台进程因为收到信号进而引起进程退出。
硬件中断的理解:当键盘按下时,通过类似8259硬件给CPU的脚针发送脉冲,其中脚针有对应的中断号,在系统中存在中断向量表,向量表中存的是对应的函数指针,中断号是向量表的下标,通过函数得知键盘哪些位置被摁下,此时OS得知了ctrl+c的按下,解释成了一个信号2,找到前台进程向其写入2号信号

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

函数一:
在这里插入图片描述
kill命令是调用kill函数实现的,kill函数可以给一个指定的进程发送指定的信号

//模拟实现kill命令
#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
using namespace std;
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        cout<<"格式是:kill -sign pid"<<endl;
        exit(1);
    }
    int pid=atoi(argv[2]);//atoi函数用来把字符串转换成整数
    int signo=atoi(argv[1]);
   int ret=kill(pid,signo);
   if(ret!=0)
   {
    cout<<"kill fails"<<endl;
    exit(2);
   }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
函数二:
在这里插入图片描述
这个函数可以给当前进程发送指定的信号(自己给自己发信号)

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
int main()
{
    int cnt=5;
    while(cnt--)
    {
        cout<<cnt<<endl;
    sleep(1);
    }
    raise(2);//五秒后进程自己给自己发2号信号
    cout<<"发送信号失败"<<endl;//如果正常发送就不能看见这句话
    return 0;
}

在这里插入图片描述
函数三:
在这里插入图片描述
absort()不会因为信号捕捉而导致无法终止,在执行完自定义处理方法后立马终止

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
 void handle(int signo)
    {
    cout<<"我是对应的"<<signo<<"信号"<<endl;
    }
int main()
{   
    handle(SIGABRT);//对应的信号是6 
    abort();
    return 0;
}

在这里插入图片描述
就像exit函数一样,abort函数总会成功

6.由软件条件产生的信号

在这里插入图片描述
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒后给当前进程发SIGALRM信号,该信号的默认处理动作是终止当前进程
这个函数的返回值是0或者是以前设定的闹钟时间还剩下的秒数。如果seconds为0,表示取消以前设定的闹钟,返回值依然是以前设定的闹钟时间还剩下的秒数

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
 void handle(int signo)
    {
    cout<<"我是对应的"<<signo<<"信号"<<endl;
    }
int main()
{
    signal(SIGALRM,handle);
    int cnt=10;
    alarm(5);//五秒后会调用自定义处理方法handle
    while (cnt--)
    {
        cout<<cnt<<endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
 void handle(int signo)
    {
    cout<<"我是对应的"<<signo<<"信号"<<endl;
    }
int main()
{
    int cnt=5;
    alarm(10);
    while (cnt--)
    {
        cout<<"倒计时:"<<cnt<<endl;
        sleep(1);
    }
    cout<<"alarm返回值"<<alarm(5)<<endl;
    return 0;
}

在这里插入图片描述
OS中有数据结构(小堆)来存闹钟,在堆顶的是距离现在最近的时间
每个进程只有一个闹钟

7.硬件异常产生信号

硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号
①当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程
在这里插入图片描述
可以发现编译的时候会报警告,但是运行时直接终止了
在这里插入图片描述
②当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGEGV信号发送给进程

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
void handle(int signo)
{
    cout << "我是对应的" << signo << "信号" << endl;
}
int main()
{
    int *p=nullptr;
    *p=10;

return 0;
}

在这里插入图片描述

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
void handle(int signo)
{
    cout << "我是对应的" << signo << "信号" << endl;
}
int main()
{
    int *p;
    *p=10;

return 0;
}

在这里插入图片描述
在这里插入图片描述
其实本质上第一步并不是直接写入100,而是先通过MMU进行虚拟地址到物理地址的转换,如果没有映射,MMU硬件报错,有映射,但没有权限,MMU直接报错,MMU报错后OS能检测到

上面两种情况都使用自定义捕捉,会出现死循环,因为当硬件出现了异常,被OS捕捉到后,会给对应的进程发信号的,但是进程没有做出什么反应,因为当CPU又执行这个进程时,异常还在,OS继续给进程发信号,所以导致了死循环

8.core

在这里插入图片描述
这当中大多数信号都是终止,但是为什么有term和core的区别?
core:终止,会先进行核心转储,然后再终止进程
term:终止就是终止,没有多余动作
之前进程退出部分中的core dump标志是为了表示是否发生核心转储
在这里插入图片描述
OS可以将该进程在异常的时候,核心代码部分进行核心转储,将内存中的进程相关数据全部dump到磁盘中,一般核心转储文件在云服务器看不到,因此默认关闭这个功能的,因为我们的是生产环境,怕多次运行,导致core文件过多
查看核心转储命令:ulimit -a
修改核心转储:ulimit -c 大小
在这里插入图片描述
在这里插入图片描述
此时在运行我们的代码

    #include <iostream>
    #include <sys/types.h>
    #include <signal.h>
    #include <cstdlib>
    #include <unistd.h>
    using namespace std;
    int main()
    {
        int a=10;
        a/=0;

    return 0;
    }

在这里插入图片描述
在这里插入图片描述
可以发现我们当前目录下多了一个core文件
那这个core文件有什么用呢?
可以通过核心转储在异常后·1,方便进行调试,在gdb通过core-file 文件名进行自动定位
在这里插入图片描述

🌸🌸信号产生的知识大概就讲到这里啦,博主后续会继续更新更多Linux的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪

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

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

相关文章

从CoCo到喜茶,新茶饮品牌领悟出海的“九阴真经”了吗?

炎炎夏日里&#xff0c;一杯冰凉的奶茶和果茶受到了更多追捧。但是&#xff0c;中国新茶饮品牌却站在了一个十字路口。 随着新茶饮迈入“万店时代”&#xff0c;国内市场已经出现了明显的内卷现象&#xff0c;头部品牌之间的竞争日趋激烈&#xff0c;中小品牌的生存空间被挤压…

OpenGL的学习记录(一)(一些基本概念)

1.OpenGL是什么&#xff1f; OpenGL是一组各个GPU厂家一起遵循的约定。 2.GLFW&#xff0c;GLAD分别是什么&#xff1f; GLFW解决系统层面的不同&#xff0c;是我们与系统之间的隔离&#xff0c;如&#xff08;创建窗口&#xff0c;定义上下文&#xff0c;处理用户输入&#x…

数据结构--树和森林的遍历

数据结构–树和森林的遍历 树的先根遍历 void PreOrder(TreeNode* R) {if (R ! NULL){visit(R);while (R还有下一个子树T)PreOrder(T);} }树和二叉树的转化后》 树的先根遍历序列与这棵树相应二叉树的先序序列相同。 \color{red}树的先根遍历序列与这棵树相应二叉树的先序序列相…

txt文本筛选—python操作

需求&#xff1a;若文档中某行最后一列内容为0&#xff0c;则删除该行&#xff0c;否则保留该行内容&#xff0c;并将筛选后的内容保存到新的文本文档中。 # 读取原始txt文件 with open(depth_values.txt, r) as file:lines file.readlines()# 过滤掉第三列内容为0的行 filter…

WIFISKY-7层流控路由器 后台任意命令执行漏洞复现

这个漏洞相当于是两个漏洞的结合&#xff0c;首先是弱口令漏洞 admin/admin 我们成功登录后台之后才能进行任意命令执行漏洞的操作&#xff0c;我们登录之后找到系统维护-系统控制台 然后我们使用命令拼接的操作来实现任意命令执行的操作 ifconfig & cat /etc/passwd

自定义seg_decoder组件并创建Nios系统(二)

3.搭建Nios Ⅱ系统 3.1添加组件 系统会自动添加一个clk的clock source组件作为时钟组件&#xff0c;可直接使用该组件作为系统时钟 添加Nios Ⅱ处理器&#xff0c;将Nios Processor组件设置框中Nios Core选择Nios Ⅱ/f&#xff08;报错先不管&#xff09; 添加On-chip Memory…

揭秘未来:AI、自然资源与时空大数据的完美结合!JNPF快速开发平台引领无限潜能!

前言 在当今数智时代&#xff0c;人工智能&#xff08;AI&#xff09;的应用正以前所未有的方式改变着各个领域的发展路径。尤其在融合自然资源、时空大数据的领域&#xff0c;AI呈现出了崭新的形式&#xff0c;展现着巨大的潜力与前景。 技术的发展离不开数据的支持 随着人工…

【STM32MP135】移除stm32mp135d-atk-u-boot.dtsi设备树config节点,否则会进入fastboot下载模式

文件路径&#xff1a;u-boot-stm32mp-v2021.10-stm32mp1-r1/arch/arm/dts/stm32mp135d-atk-u-boot.dtsi

TVS二极管原理

在管子两端的电压大于一定值时&#xff0c;TVS管被反向击穿&#xff0c;瞬间形成一个导通回路&#xff0c;将管子两端的大电流导出&#xff0c;并且将管子两段的电压钳制在一个固定电压&#xff0c;进而保护和它并联的电路。 挑选TVS管先看VRWM&#xff0c;尽量与最大工作电压接…

洛谷:P5018 对称二叉树 ← NOIP2018 普及组T4

【题目来源】https://www.luogu.com.cn/problem/P5018https://www.acwing.com/problem/content/478/【题目描述】一棵有点权的有根树如果满足以下条件&#xff0c;则被轩轩称为对称二叉树&#xff1a; 1.二叉树&#xff1b; 2.将这棵树所有节点的左右子树交换&#xff0c;新树和…

关于Python的Numpy库reshape()函数的用法

1.介绍 更改数组的形状&#xff0c;不改变原数组 2.语法 a np.reshape(mat, newshape, order ‘C’) a : newshape形状的新数组 mat : 原数组 newshape&#xff1a;(1, 2)/ 1, 2 都可以改为1行2列的数组 order&#xff1a;读取原数组的规则&#xff0c;默认为C&#xff08;…

Go语言精进之路读书笔记—第三章 声明、类型、语句与控制结构(五)map

map 是啥&#xff1f; 无序的 key value 键值对。 创建变量有两种方式&#xff1a; 基本操作&#xff1a; 插入数据&#xff1a; 获取数据&#xff1a; 查找和数据读取&#xff1a; comma ok 查找法, 被称为最佳实践。 获取value 删除数据 遍历数据 想要有序的需要这样做&a…

CSS 沿着同一个方向旋转

主要解决旋转360后倒转的问题&#xff0c;沿着一个方向旋转&#xff0c;而不是倒回去重新开始。 效果 源码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>同方向旋转</title><script src"https://dp.rc1…

【STM32MP135】修复EMMC模式启动时,uboot启动识别为usb0设备问题

文件路径&#xff1a;u-boot-stm32mp-v2021.10-stm32mp1-r1/arch/arm/dts/stm32mp135d-atk.dts 文件路径&#xff1a;u-boot-stm32mp-v2021.10-stm32mp1-r1/configs/stm32mp13_defconfig

ChatGLM 实践赛之学术工具创意开发丨智谱 AI × 和鲸科技

2022 年底以来&#xff0c;LLM 大规模语言模型备受瞩目。今年 3 月中旬&#xff0c;智谱 AI 与清华大学强强联合&#xff0c;重磅发布了 ChatGLM-6B 开源模型。截止 6 月 24 日&#xff0c;该模型的下载量超过三百万人次&#xff0c;并在 Hugging Face&#xff08;HF&#xff0…

jdbc中jdbcTemplate的事务问题

jdbcTemplate的增删改都用 update 查询用queryForList 1. 2. 3.虽然事务未提及也可以查到对应的数据

优思学院|六西格玛全面入门指南

I. 引言 六西格玛的定义 六西格玛&#xff08;Six Sigma&#xff09;是一种基于数据、以客户为导向、不断改进的方法论&#xff0c;用于提高组织中过程和产品的质量。六西格玛旨在消除缺陷&#xff0c;减少过程中的变异性&#xff0c;从而提高客户体验&#xff0c;并增加组织…

pip install visdom时报错

在envs所在环境下pip install visdom报如下错误&#xff1a; 解决方法&#xff0c;换源&#xff1a; pip install visdom -i https://pypi.tuna.tsinghua.edu.cn/simple

基于Web的社区医院管理服务系统

本次设计任务是要设计一个社区医院管理服务系统&#xff0c;通过这个系统能够满足社区医院管理服务的管理及医生和用户的社区医院管理服务功能。系统的主要功能包括首页、个人中心、用户管理、医生管理、预约医生管理、就诊信息管理、诊疗方案管理、病历信息管理、健康档案管理…

Vue3 使用vue-seamless-scroll 轮播组件报错问题解决

1、npm安装组件 npm install vue3-seamless-scroll --save 全局注册 import { createApp } from vue;import App from ./App.vue;import vue3SeamlessScroll from "vue3-seamless-scroll";const app createApp(App);app.use(vue3SeamlessScroll);app.mount(#app); …