【Linux】进程信号篇:信号的产生(signal、kill、raise、abort、alarm)、信号的保存(core dump)

news2024/11/18 1:46:46

文章目录

  • 一、 signal 函数:用户自定义捕捉信号
  • 二、信号的产生
    • 1. 通过中断按键产生信号
    • 2. 调用系统函数向进程发信号
      • 2.1 kill 函数:给任意进程发送任意信号
      • 2.2 raise 函数:给调用进程发送任意信号
      • 2.3 abort 函数:给调用进程发送 6 号信号
    • 3. 软件条件产生信号
      • alarm 函数:闹钟时间后,发送 14(SIGALRM )号信号
    • 4. 硬件异常产生信号
      • 4.1 除0:8) SIGFPE
      • 4.2 野指针:11) SIGSEGV
  • 三、信号保存的细节
    • 1. core 和 term
    • 2. waitpid 中,status 第八位的 core dump 标志位


kill -l 可以查看所有信号:

在这里插入图片描述
其中,前面的数字就是信号,后面的大写英文就是信号名称,实际就是宏。

我们需要关注的是 1~31 号普通信号,关注他们有没有产生(可以用 0 或者 1 表示)。

所以,进程的 pcb 中,需要对产生的信号先用 位图 保存起来,再按照一定的顺序去处理他们。

我们所谓发送信号,本质其实就是写入信号,直接修改特定进程的信号位图中的特定比特位(0 / 1)。位图中,比特位的位置,是信号的编号;比特位的内容表示,是否收到该信号。

无论后面有多少种信号产生的方式,最终都必须要让 OS 来完成最后发送 / 写入的过程。

man 7 signal:查看所有信号详细信息
在这里插入图片描述


一、 signal 函数:用户自定义捕捉信号

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

参数 signum:

  • 信号编号


参数 handler:

  • 用户自定义处理动作,在 signum 信号发生时触发。

🌰使用举例:

// 自定义方法
// signo:特定信号被发送给当前进程的时候,执行handler方法的时候,要自动填充对应的信号给handler方法
// 我们甚至可以给所有的信号设置同一个处理函数
void handler(int signo)
{
    std::cout << "get a singal: " << signo << std::endl;
    // exit(2);
}


int main()
{
    // signal(SIGINT, handler);
    // signal(SIGQUIT, handler);

    signal(2, handler);	// 2:ctrl+c
    signal(3, handler);	// 3:ctrl+\
    while(true)
    {
        std::cout << "我是一个进程,我正在运行 ..., pid: " << getpid() << std::endl;
        sleep(1);
    }

    return 0;
}
1. 2号信号,进程的默认处理动作是终止进程
2. signal 可以进行对指定的信号设定自定义处理动作
3. signal(2, handler)调用完这个函数的时候,handler方法没有被调用,只是更改了2号信号的处理动作。
4. 那么handler方法在当2号信号产生的时候才会被调用
5. 默认我们对2号信号的处理动作:终止进程,我们用signal(2, handler), 我们在执行用户动作的自定义捕捉!不是每个信号我们都可以自定义捕捉的!!比如 9 就不行。是 OS 规定的

二、信号的产生

1. 通过中断按键产生信号

比如用户按下 ctrl+c,键盘输入产生一个 硬件中断,用电信号将中断号写入寄存器,系统再根据中断号去中断向量表中查找,然后 OS 再从键盘中去读取数据(看是键盘哪些位置被摁下)。被 OS 获取后,解释成信号,发送给目标前台进程。

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

2.1 kill 函数:给任意进程发送任意信号

头文件

#include <signal.h>

int kill(pid_t pid, int sig);

参数 pid:

  • 进程pid

参数 sig:

  • 信号

2.2 raise 函数:给调用进程发送任意信号

头文件

#include <signal.h>

int raise(int sig);

参数 sig:

  • 信号

2.3 abort 函数:给调用进程发送 6 号信号

头文件

#include <stdlib.h>

void abort(void);

进程收到 6 号信号就会终止,即使可以被用户捕捉到,也会完成终止。

3. 软件条件产生信号

(SIGPIPE也是一个由软件条件产生的信号

alarm 函数:闹钟时间后,发送 14(SIGALRM )号信号

默认动作是终止(Term)当前进程
头文件

#include <unistd.h>

unsigned alarm(unsigned seconds);

参数 seconds:

  • 时间


返回值:

  • 0,或者是以前设定的闹钟时间还余下的秒数。(比如第一次提前结束,在次重新设定时,就会返回之前剩余的时间)

alarm 函数是一次性的,可以利用捕捉器,进行 自取 操作,达到不断设置闹钟的作用。

🌰使用举例:

void myhandler(int signo)
{
    std::cout << "get a signal: " << signo << " count: " << count << std::endl;
    alarm(1);
    // exit(0);
}

int main(int argc, char *argv[])
{
    std::cout << "pid: " << getpid() << std::endl;
    signal(SIGALRM, myhandler);
    alarm(1); //一次性的

    while(true)
    {
        sleep(1);
    }
}

alarm 也是有内核数据结构的,OS 管理这些内核数据结构,每隔一段时间就会去比如说管理 alarm 的最小堆中,当堆顶 timestamp >= 系统当前时间 时,就会给这个对应的进程 pid 发送 SIGALRM 信号,并把这个闹钟从堆中拿走。

struct alarm
{
	int timestamp; // curr + 设置的seconds
	// ...进程 pid ...等等
};

4. 硬件异常产生信号

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

4.1 除0:8) SIGFPE

SignalValueActioncomment
SIGFPE8CoreFloating point exception

例如当前进程执行了除 0 的指令,CPU的运算单元会产生异常,内核将这个异常解释为 SIGFPE 信号,发送给进程。

状态寄存器:用比特位表示状态,其中有一位,就是反映本次计算是否有溢出问题。

出现除 0 后,溢出标志位被置 1,os 发现后立即将 相应进程 pcb 中发送 8号 信号。

4.2 野指针:11) SIGSEGV

SignalValueActioncomment
SIGSEGV11CoreInvalid memory reference

再比如当前进程访问了非法内存地址,MMU 会产生异常,内核将这个异常解释为 SIGSEGV 信号发送给进程。

虚拟地址 通过页表 转换访问到物理内存,这个过程其实是软硬件结合的方式完成的。这个页表的 KV 转换过程就是由硬件 MMU 完成的。

MMU:内存管理单元,被集成在 CPU 内,转换时,只需要把虚拟地址导入到 MMU 这个硬件中,用这个硬件转。

🌰举例:

// 一个野指针问题
int *p = nullptr;
p* = 100;

分析上述代码,当我们赋值给指针为 nullptr 时,p 里面放的是 0 或者 nullptr,*p 代表的就是虚拟地址空间中的 0 号地址,我们想将 100 写入 0 号地址,但这个地址我们没有申请过,他也不允许我们访问,所以造成了野指针 / 悬垂指针问题。

其实,*p = 100;第一步并不是写入,而是首先进行虚拟地址到物理内存的转换。

  • 没有映射:MMU 硬件报错
  • 有映射,但是没有权限:MMU 直接报错
  • OS 接收到报错后,传递给 CPU 中的一个寄存器,找到相应进程的 pcb 对其发送 11号 信号。

三、信号保存的细节

1. core 和 term

查看信号的 Action 栏有 core 和 term 两种。

他们有什么不同呢?

在这里插入图片描述

  • term 终止的就是终止,没有多余的动作。

  • core 终止,会先进行核心转储,再进行终止。

进程在异常的时候,OS 可以将该核心代码部分进行 核心转储,将内存中进程的相关数据,全部 dump 到磁盘中。核心转储的目的是,方便异常后进行调试。

一般核心转储文件在云服务器上确实看不到,而是云服务器默认是关闭这个功能的!ulimit -a 可以查到 core_file_size 大小是0,即关闭的,按照提示 ulimit -c [数值] 设置大小,即可打开核心转储功能,数值设为 0 就是关闭。

当程序异常时,我们不知道哪里出了问题。有如下解决方法,称作 事后调试

  • -g 生成可执行程序,使用 gdb 命令打开调试模式

  • 命令行中输入:core-file core.xxxx (xxxx 为相应的核心转储生成文件),就会出现报错原因的详细信息,和报错位置

既然核心转储那么方便,为什么云服务器要关闭这个功能呢?

Linux环境根据使用目的可以分为:开发环境、测试环境、生产环境
云服务器属于生产环境,生产环境是默认关闭核心转储的!

按照 CPU 的运行速度,错误的代码,在短时间内可以造成大量的 core. 文件,磁盘写满甚至系统崩溃都是有可能的,所以生产环境下,一般都是将这个功能关闭的。

2. waitpid 中,status 第八位的 core dump 标志位

在这里插入图片描述

这里的 core dump 标志位,就是用来记录,是否有 core dump 出现的。

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

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

相关文章

Rest学习环境搭建:服务提供者

创建一个普通的Maven项目 pom.xml父工程 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

科大讯飞发布星火认知大模型2.0版——体验实测

8月15日&#xff0c;科大讯飞举行讯飞星火认知大模型V2.0升级发布会&#xff0c;对外展示其升级后的大模型代码能力和多模态能力&#xff0c;同时发布并升级搭载讯飞星火认知大模型V2.0能力的多项应用和产品。自5月6日首发以来&#xff0c;星火认知大模型经历V1.5版本的迭代&am…

面试之快速学习STL-deuqe和list

1. deque deque 容器用数组&#xff08;数组名假设为 map&#xff09;存储着各个连续空间的首地址。也就是说&#xff0c;map 数组中存储的都是指针如果 map 数组满了怎么办&#xff1f;很简单&#xff0c;再申请一块更大的连续空间供 map 数组使用&#xff0c;将原有数据&…

利用Figlet工具创建酷炫Linux Centos8服务器-登录欢迎界面-SHELL自动化编译安装代码

因为我们需要生成需要的特定字符,所以需要在当前服务器中安装Figlet,默认没有安装包的,其实如果我们也只要在一台环境中安装,然后需要什么字符只要复制到需要的服务器中,并不需要所有都安装。同样的,我们也可以利用此生成的字符用到脚本运行的开始起头部分,用ECHO分行标…

go_并发编程(1)

go并发编程 一、 并发介绍1&#xff0c;进程和线程2&#xff0c;并发和并行3&#xff0c;协程和线程4&#xff0c;goroutine 二、 Goroutine1&#xff0c;使用goroutine1&#xff09;启动单个goroutine2&#xff09;启动多个goroutine 2&#xff0c;goroutine与线程3&#xff0…

log4j:WARN No appenders could be found for logger问题

本文将idea场景下的使用。 IDEA中&#xff0c;将配置文件命名为log4j.properties&#xff08;该命名才会被自动加载&#xff09;&#xff0c; 并放到某个目录下&#xff08;通常放到resources目录&#xff09;&#xff0c;并在resources上右键&#xff0c;找到Mark Directory a…

(二)结构型模式:8、代理模式(Proxy Pattern)(C++示例)

目录 1、代理模式&#xff08;Proxy Pattern&#xff09;含义 2、代理模式的UML图学习 3、代理模式的应用场景 4、代理模式的优缺点 5、C实现代理模式的实例 1、代理模式&#xff08;Proxy Pattern&#xff09;含义 代理模式&#xff08;Proxy&#xff09;&#xff0c;为…

【LangChain】P1 LangChain 应用程序的核心构建模块 LLMChain 以及其三大部分

LangChain 的核心构建模块 LLMChain LangChain 应用程序的核心构建模块语言模型 - LLMs提示模板 - Prompt templates输出解析器 - Output Parsers LLMChain 组合 LangChain 应用程序的核心构建模块 LangChain 应用程序的核心构建模块 LLMChain 由三部分组成&#xff1a; 语言…

【Git】(四)子模块

1、增加子模块 进入准备添加子模块所在的目录&#xff0c;例如library。 git submodule add -b 1.0.0.0 gitgitee.com:sunriver2000/SubModule.git参数-b用于指定子模块分支。 2、更新子模块 git submodule update --progress --init --recursive --force --remote -- "…

小程序前台Boot后台校园卡资金管理系统java web学校进销存食堂挂失jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 小程序前台Boot后台校园卡资金管理系统 系统有2权限&…

fastadmin 下拉多级分类

要实现下图效果 一、先创建数据表 二、在目标的controll中引入use fast\Tree; public function _initialize() {parent::_initialize();$this->model new \app\admin\model\zxdc\Categorys;$tree Tree::instance();$tree->init(collection($this->model->order(…

Springboot写单元测试

导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintag…

探索高级UI、源码解析与性能优化,了解开源框架及Flutter,助力Java和Kotlin筑基,揭秘NDK的魅力!

课程链接&#xff1a; 链接: https://pan.baidu.com/s/13cR0Ip6lzgFoz0rcmgYGZA?pwdy7hp 提取码: y7hp 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f4da;【01】Java筑基&#xff1a;全方位指…

【Go】Go 文本匹配 - 正则表达式

正则表达式&#xff08;Regular Expression, 缩写常用regex, regexp表示&#xff09;是计算机科学中的一个概念&#xff0c;很多高级语言都支持正则表达式。 目录 何为正则表达式 语法规则 普通字符 字符转义 何为正则表达式 正则表达式是根据一定规则构建而出的规则&…

【广州华锐视点】帆船航行VR模拟实操系统

帆船航行VR模拟实操系统由广州华锐视点开发&#xff0c;是一种创新的教学工具&#xff0c;它利用虚拟现实技术&#xff0c;为学生提供了一个沉浸式的学习环境。通过这种系统&#xff0c;学生可以在虚拟的环境中进行帆船航行的实训&#xff0c;从而更好地理解和掌握帆船航行的技…

腾讯云3年轻量应用服务器2核4G5M和2核2G4M详细介绍

腾讯云轻量应用服务器3年配置&#xff0c;目前可以选择三年的轻量配置为2核2G4M和2核4G5M&#xff0c;2核2G4M和2核4G5M带宽&#xff0c;当然也可以选择选一年&#xff0c;第二年xufei会比较gui&#xff0c;腾讯云百科分享腾讯云轻量应用服务器3年配置表&#xff1a; 目录 腾…

云原生 envoy xDS 动态配置 java控制平面开发 支持restful grpc

envoy xDS 动态配置 java控制平面开发 支持restful grpc 大纲 基础概念Envoy 动态配置API配置方式动静结合的配置方式纯动态配置方式实战 基础概念 Envoy 的强大功能之一是支持动态配置&#xff0c;当使用动态配置时&#xff0c;我们不需要重新启动 Envoy 进程就可以生效。…

数据结构的图存储结构

目录 数据结构的图存储结构 图存储结构基本常识 弧头和弧尾 入度和出度 (V1,V2) 和 的区别,v2> 集合 VR 的含义 路径和回路 权和网的含义 图存储结构的分类 什么是连通图&#xff0c;&#xff08;强&#xff09;连通图详解 强连通图 什么是生成树&#xff0c;生…

Python之Qt输出UI

安装PySide2 输入pip install PySide2安装Qt for Python&#xff0c;如果安装过慢需要翻墙&#xff0c;则可以使用国内清华镜像下载&#xff0c;输入命令pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple PySide2&#xff0c;如下图&#xff0c; 示例Demo i…

每天一道leetcode:1192. 查找集群内的关键连接(图论困难tarjan算法)

今日份题目&#xff1a; 力扣数据中心有 n 台服务器&#xff0c;分别按从 0 到 n-1 的方式进行了编号。它们之间以 服务器到服务器 的形式相互连接组成了一个内部集群&#xff0c;连接是无向的。用 connections 表示集群网络&#xff0c;connections[i] [a, b] 表示服务器 a …