Linux进程信号

news2024/11/15 9:33:48

文章目录

    • 什么是信号
    • signal函数的功能(捕捉信号后自己处理)
    • Core Dump(核心转储)
    • kill,raise,alarm系统调用
    • 再度理解OS给进程发送信号
    • 信号集操作函数
    • 自定义捕捉详解

什么是信号

生活中的信号:闹钟,红绿灯,鸡叫声,,,,,,
这些场景触发的时候我们就知道自己该做什么了。 在信号产生之前,我们也知道遇到什么信号该做什么事情。
同样的,我们受到信号以后也不一定马上会去执行,也有可能信号发出来了,我们收不到的情况。
例如闹钟在客厅响了,你戴着耳机在卧室和女朋友一起愉快的开黑玩游戏,这时候你就听不到信号,听到了也不想管。

同样的信号产生后,是OS给进程发送的,向进程内核数据结构task_struct写入信号数据
同样的道理,进程收到信号以后也像我们人一样收到信号。 未收到的时候知道该如何处理,不立即处理,暂时保存信号数据,
到时候再处理,也有可能不处理或者收不到信号

也就是进程处理信号的方式:
1,忽略此信号。
2,执行该信号的默认处理动作。
3,提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉
(Catch)一个信号。

如何产生信号:
1,键盘产生(只作用于前台进程,./test & 就变成了后台进程)
后台程序基本上不和用户交互,优先级别稍微低一点
前台的程序和用户交互,需要较高的响应速度,优先级别稍微高一点
2,程序中的异常问题,导致进程受到信号而退出
3,通过系统调用去产生信号
4,软件条件产生信号。(例如在匿名管道中,读端关闭,写端收到13信号后关闭)

例如进程在死循环的时候,我们在键盘上输入ctrl+c,实际上就是通过OS给该进程发送了2号信号
在这里插入图片描述

kill -l 可以查看信号对应的编号信息。
在这里插入图片描述

man 7 signal 可以查看受到编号信号后进程的默认动作。
在这里插入图片描述

signal函数的功能(捕捉信号后自己处理)

其中9号进程无法被定义。
在这里插入图片描述

Core Dump(核心转储)

1,在Linux中,当一个进程退出的时候,它的退出码和退出信号都会被设置(正常情况)
2,如果进程异常,进程的退出信号会被设置表明进程退出的原因,如果必要,OS会设置core dump标志位。
在这里插入图片描述

什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部 保存到磁
盘上,文件名通常是core,这叫做Core Dump
默认是不允许产生core文件的,
因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许
产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: $ ulimit -c
1024

有什么作用呢? 方便我们调试,寻找到错误所在的地方。
但是要注意一下,Linux下默认是release版本,编译的时候要 + -g

在这里插入图片描述

说到这里,顺便复习下gdb的调试功能把
r 是运行
l 列出代码
s 逐语句
b 是设置断点
info b 查看断点
p sum 查看sum的值,值显示一次
display sum 常显示
undispaly 不显示
d x 删除编号x的断点

kill,raise,alarm系统调用

在这里插入图片描述

kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。
raise函数可以给当前进程发送指定的信号(自己给自己发信号)。
alarm()函数 比较简单,就不做演示了。

 int main()
 10 {
 11      int pid = fork();
 12      if(pid < 0)
 13      {
 14        perror("fork");
 15        exit(-1);
 16      }
 17 
 18      if(pid == 0)
 19      {
 20        sleep(5);
 21        printf("I am a child");                                                                                                               
 22        kill(getppid(),2); // 给父进程发送2号信号ctrl c终止
 23      }
 24      else
 25      {
 26         while(1)
 27         {
 28           printf("I am panret\n");
 29           sleep(1);
 30         }
 31 
 32      }
         
 35      return 0;
 36 }

4 int main()                            
 15 {                                     
 16     int count = 0;                    
 17     while(1)                          
 18     {                                 
 19        printf("hello chen\n");        
 20        count++;                       
 21                                       
 22        if(count == 10)                
 23          raise(9); //自己给自己发送9号信号                                                                                                   
 24     }
 25   
 26     return 0;
 27 }            
 28     

再度理解OS给进程发送信号

实际上就是OS向进程控制块写入数据
信号递达(如何处理信号的动作):1,自定义捕捉。 2,默认处理。3,忽略
未决:信号暂存于task_struct中,(还未处理)
阻塞:OS运行进程暂时屏蔽指定信号
1,该信号还是未决状态,2,该信号不能被处理,直到解除阻塞

下图的SIG_DEL是默认动作,SIG_IGN是忽略动作。
在这里插入图片描述

总结:
上面所说的所有信号产生,最终都要有OS来进行执行,为什么?
因为OS是进程的管理者,所以无论信号如何产生,最终都是通过OS来发送给进程的。

信号的处理是否是立即处理的?
在合适的时候(就是由内核态转换为用户态的时候,后面详细说明)

信号如果不是被立即处理,那么信号是否需要暂时被进程记录下来?记录在哪里最合适呢?
信号肯定会被立即记录,记录在进程的PCB中

一个进程在没有收到信号的时候,能否能知道,自己应该对合法信号作何处理呢?
肯定知道。如果不知道的话,进程收到信号难道原地发呆吗?

如何理解OS向进程发送信号?能否描述一下完整的发送处理过程?
当信号产生后,OS找到对应进程的PCB,向PCB中写入相关的信号数据,将进程PCB中的pending位图相应位置置1,
如果block位图中的相应信号编号位置是阻塞,则等到解除阻塞后再执行。
如果不是阻塞,则从handler表(函数指针数组)进行递达。
递达方式有忽略,默认,自定义。
忽略直接将pending位图直接置0.
默认,OS直接执行。
如果是自定义,由内核态进入用户态,切换成用户身份后来执行相应的代码和数据,然后返回内核态,再返回用户态最终处理完成。

信号集操作函数

OS提供系统调用接口,那肯定也提供了相应的数据类型。
例如sigset_t 是信号集类型,只能由OS提供的系统调用去处理
#include <signal.h>

int sigemptyset(sigset_t *set);  //全部置0
int sigfillset(sigset_t *set);   //全部置1
int sigaddset (sigset_t *set, int signo);  //相应位置置1
int sigdelset(sigset_t *set, int signo);   //相应位置置0
int sigismember(const sigset_t *set, int signo)  //检查相应位置是否为1 

sigprocmask 和sigpending
sigprocmask

来段代码操作一下

8 void showsigpending(sigset_t* set)
  9 {    
 10     int i = 1;                                         
 11     for(i = 1; i <= 31; i++)
 12     {       
 13         if(sigismember(set,i))  //如果未决存在,则输出1
 14          printf("1");
 15         else       
 16           printf("0");
 17     }
 18     fflush(stdout);
 19     printf("\n");                                                                                                                            
 20 }         
 21  
 22                  
 23 int main()          
 24 {                                              
 25     sigset_t s,p;
 26     sigemptyset(&s);                                           
 27     sigisemptyset(&p);   //这个用来获取未决状态                         
 28 
 29     sigaddset(&s,2); //将s里面信号集中的二号信号设为1  ctrl + c
 30     sigprocmask(SIG_SETMASK,&s,NULL); // 阻塞2号,不关心之前的信号屏蔽字
 31 
 32     while(1)
 33     {
           sigpending(&p);  //获取当前信号的未决 集
 35         showsigpending(&p);
 36         sleep(1);
 37     }
 
 41     return 0;
 42 }

   

在这里插入图片描述

自定义捕捉详解

我们分析一下递达方式:自定义捕捉,当我们发送特定信号的时候,去执行用户给的自定义函数。

要说清这个,需要知道用户态和内核态的区别。
用户态:只能执行用户的代码,使用用户的数据所处的状态,其中用户以进程为代表(可理解为进程就是用户,但并不准确)
内核态:只能执行OS的代码和数据,所处的状态。
之间的根本区别:就是权限问题。 OS是进程的管理者,意味着内核态的权限非常大。
在这里插入图片描述

解析:
1过程,为什么要切换内核态呢? OS是进程的管理者,进程出现异常,肯定由OS发送信号通知。
3过程为什么要返回用户态去执行呢? 如果不返回在内核态执行用户态的代码这肯定是不允许的,为什么呢?
内核态的权限非常大,万一来一个 rm -rf / ,OS不就凉凉了吗。
4过程,执行完后为什么要返回呢?main 和handler不属于调用的关系,完全是两个独立的执行流,所以无法从handler返回到main()
所以handler()执行完后,只能借助相应的系统调用函数,返回内核后,在从内核返回main的执行流
在这里插入图片描述

简单记忆:数学符号无穷大
在这里插入图片描述

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

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

相关文章

0083 环形链表

package LinkedList_; /* * 单向环形链表应用场景——约瑟夫问题 * 设编号为1&#xff0c;2....n的n个人围成一圈&#xff0c;约定编号为k&#xff08;1<k<n&#xff09;的人从1开始报数&#xff0c;数到m的人出列&#xff0c; * 它的下一位又从…

黑胶歌曲没权限,还好我会Python,一分钟一个歌单,硬盘有点不够用了~

今日份Python白嫖人生苦短&#xff0c;我用Python一、你需要准备1、环境2、模块二、效果展示三、代码展示四、写在最后人生苦短&#xff0c;我用Python 人之初&#xff0c;喜白嫖。大家都喜欢白嫖&#xff0c;我也喜欢&#xff0c;那么今天就来试试怎么白嫖抑云~ 我不是&#…

React面向组件编程(定义组件,组件三大核心属性,组件事件处理、组件收集表单数据、高阶函数和函数的柯里化)

目录 一、React中定义组件 1、函数式组件 2、类式组件 二、组件三大核心属性 1、组件三大核心属性1: State(状态) 2、组件三大核心属性2: props 3、组件三大核心属性3: ref 三、组件事件处理 1、事件处理 四、组件收集表单数据 1、受控组件 2、非受控组件 五、高阶函…

【数据结构】算法的时间复杂度和空间复杂度

&#x1f680; 作者简介&#xff1a;一名在后端领域学习&#xff0c;并渴望能够学有所成的追梦人。 &#x1f40c; 个人主页&#xff1a;蜗牛牛啊 &#x1f525; 系列专栏&#xff1a;&#x1f6f9;初出茅庐C语言、&#x1f6f4;数据结构 ☀️ 学习格言&#xff1a;眼泪终究流不…

象棋中的马跳步问题

象棋中的马跳步问题 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;象棋中的马跳步问题 CSDN&#xff1a;象棋中的马跳步问题 题目描述 中国象棋中&#xff0c;整个棋盘就是横坐标上 9 条线、纵坐标上 10 条线的一个区域&#xff0c;给你三个 参数 x&…

计算机毕业设计springboot+vue基本微信小程序的汽车租赁公司小程序

项目介绍 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时…

【Vue】环境搭建

Vue 简介&#xff1a; 一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。另一方面&#xff0c;当与现代化的工具链以…

Jenkins+Docker 一键自动化部署 SpringBoot 项目

本文章实现最简单全面的 Jenkins Docker Spring Boot 一键自动部署项目。步骤齐全&#xff0c;少走坑路。 环境&#xff1a;CentOS7 Git (Gitee) 实现步骤&#xff1a;在 Docker 安装 Jenkins&#xff0c;配置 Jenkins 基本信息&#xff0c;利用 Dockerfile 和 Shell 脚本实…

CSS 的布局 盒子

目录 块级元素和行内元素 块级元素 特点&#xff1a; 行内元素 特点&#xff1a; 行内元素 和 块级元素 的区别 改变显示模式&#xff08;把行内元素 变成 块级元素) 盒模型 盒模型图 边框基础属性 内边框、外边框 基础写法&#xff1a; 复合写法 块级元素水平居中 前提&#…

C++知识点大全(第二版)

目录 1 C简介 1.1 起源 1.2 应用范围 1.3 C和C 2开发工具 3 基本语法 3.1 注释 3.2关键字 3.3标识符 4 数据类型 4.1基本数据类型 4.2 数据类型在不同系统中所占空间大小 4.3 typedef声明 4.4 枚举类型 5 变量 5.1 变量的声明和定义 5.2 变量的作用域 6 运算…

如何当好硬软件助理工程师——实习周报(一)

如何当好硬软件助理工程师——实习周报 如何当好硬软件助理工程师——实习周报&#xff08;一&#xff09; 文章目录如何当好硬软件助理工程师——实习周报前言一、问题积累1.git 指令2.Coding的使用3.代码中的知识点&#xff08;HAL库、Flash读写&#xff09;a.gpio配置b.fla…

程序员必备的画图工具汇总

文章目录1、简介2、draw.io3、Excalidraw4、Xmind5、语雀6、Database6.1 dbdiagram.io6.2 sqldbm6.3 QuickDBD7、UML7.1 plantuml7.2 Graphviz结语1、简介 优秀的作图工具有许多&#xff0c;例如文本绘图工具 PlantUML&#xff0c;流程图设计工具 Draw.io&#xff0c;还有专业…

ORA-01861: literal does not match format string

系统&#xff1a;AnolisOS7.9 数据库&#xff1a;Oracle11.2.0.4 问题描述&#xff1a;执行TSPITR时&#xff0c;报错ORA-01861&#xff0c;如下所示&#xff1a; [oracleliujun~]$ export NLS_DATE_FORMATyyyy-mm-dd hh24:mi:ss [oracleliujun~]$ export NLS_LANGAMERICAN…

手写Mybatis源码(原来真的很简单!!!)

目录一、JDBC操作数据库_问题分析二、自定义持久层框架_思路分析三、自定义框架_编码1、加载配置文件2、创建两个配置类对象3、解析配置文件&#xff0c;填充配置类对象4、创建SqlSessionFactory工厂接口及DefaultSqlSessionFactory实现类5、创建SqlSession会话接口及DefaultSq…

R语言和医学统计学(10):正态性和方差齐性检验

本文首发于公众号&#xff1a;医学和生信笔记&#xff0c;完美观看体验请至公众号查看本文。 医学和生信笔记&#xff0c;专注R语言在临床医学中的使用&#xff0c;R语言数据分析和可视化。 文章目录前言正态性检验shapiro wilk检验kolmogorov smimov检验方差齐性检验两样本方差…

SSH框架重构需求,起码读懂代码和前端的原生JS

文章目录SSH(Spring Struts Hibernate)商城老项目JSPHtmlJsJquery 老项目部署Tomcat上面进行部署可以一次性部署多个项目1.Spring2.Struts3.Hibernate(持久层一个重量级框架)4.里面的请求路径解析SSH(Spring Struts Hibernate)商城老项目JSPHtmlJsJquery 老项目部署 Tomca…

【JavaSE之JDK8新特性】三万字详文带你了解JDK8新特性

JDK8新特性一、Lambda1.1需求分析2.Lambda表达式的初级体验3.Lambda表达式的语法规则3.1.Lambda练习13.2.Lambda表达式练习24.FunctionalInterfa注解说明5.Lambda表达式的原理6.Lambda表达式的省略写法7.lambda表达式的使用前提8.lambda和匿名内部类的对比二、接口中新增的方法…

#define宏的妙用!实现你以为的函数offsetof等

目录 一.#define 1.1#define的使用 1.2在define定义标识符的时候&#xff0c;要不要在最后加上 ;? 二.#define定义宏 2.1好代码的写法: 2.2#define 替换规则 2.3#和## 三.带有副作用的宏参数 四.宏和函数的对比 五.实现offetof 思路解析过程&#xff1a; 代码实现&am…

破解系统密码

一、利用5次shift漏洞破解win7密码 1.1 漏洞 1. 在未登录时&#xff0c;连续按5次shift键&#xff0c;弹出程序C:\Windows\System32\sethc.exe 2. 部分win7及win10系统在未进入系统时&#xff0c;可以通过系统修复漏洞篡改系统文件名&#xff01; 注意&#xff1a;如win7或win…

SpringBoot/Spring AOP默认动态代理方式

Spring 5.x中AOP默认依旧使用JDK动态代理SpringBoot 2.x开始&#xff0c;AOP为了解决使用JDK动态代理可能导致的类型转换异常&#xff0c;而使用CGLIB。在SpringBoot 2.x中&#xff0c;AOP如果需要替换使用JDK动态代理可以通过配置项spring.aop.proxy-target-classfalse来进行修…