Linux操作系统~进程崩溃的原理是什么?信号的产生方式有哪些?

news2025/1/11 16:48:18

目录

1.信号的概念

2.signal函数的使用

kill -l

自定义信号处理函数signal函数

3.进程异常/崩溃的原理

(1).进程为什么会崩溃?

(2).如何知道进程崩溃/异常的原因

(3).core dump的作用——可以知道在哪一行崩溃的

4.信号的产生方式

系统调用产生信号(kill,raise,abort函数)

软件条件产生信号(alarm函数)


1.信号的概念

        1.信号的产生->信号是给进程发的->进程要在合适的时候,要执行对应的动作

        2.进程在没有收到信号的时候,进程已经知道应该如何识别是哪一个信号以及如何处理它,曾经的操作系统工程师在写进程源代码的时候,就已经设置好了。

进程具有识别信号并处理信号的能力,远远早于信号的产生的

        3.信号随时都可能产生(异步),(异步信号发出后不需要等待其响应返回,发出者可以直接去做别的事情,所以收到信号的人可以先不作出响应,继续做自己更重要的事情),但是我当前可能做着更重要的事情!

进程收到信号之后,需要先将信号保存起来,以供在合适的时候处理!

        4.保存在哪里呢?进程的PCB也就是task_struct里面

信号本质也是:数据!

信号的发送->往进程task_struct内写入信号数据!

        5.无论我们的信号任何发送,本质都是在底层通过OS发送的

信号的整个生命周期:

        信号产生前(信号产生的各种方式)——信号产生中(信号保存的方式)——信号产生后(信号处理的方式)


2.signal函数的使用

kill -l

kill -l可以查看系统支持的信号

键盘Ctrl+C的时候本质上是向进程发送2号信号

前31个是普通信号,后31个是实时信号

[zebra@VM-8-12-centos cpp]$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
[zebra@VM-8-12-centos cpp]$ 

自定义信号处理函数signal函数

signal函数:修改进程对信号的默认处理动作

  • signum:表示要修改几号信号
  • handler表示要做出的处理动作函数

e.g.:

siganl.cc:

#include <iostream>
#include <signal.h>
#include <unistd.h>

using namespace std;
void handler(int signo)
//传入的信号表示要对几号信号进行自定义处理
{
    printf("get a signal no: %d, pid: %d\n",signo, getpid());  //打印执行的是几号信号的处理函数,打印执行
}

int main()
{
    signal(2,handler);  //通过signal注册2号信号的处理动作,改成自定义处理动作
    while(1)
    {
        cout << "zebra, pid :" << getpid() << endl << endl;
        sleep(1);
    }
    return 0;
}

        当我们使用kill -2向对应进程发送2号信号,或者使用Ctrl+C发送2号信号的时候,会回调handler方法,执行我们自己定义的对2号信号的处理动作

        信号的产生方式其中一种就是通过键盘产生键盘产生的信号只能用来终止前台进程

        如果我们运行进程的时候加上一个&,让进程在后台运行,此时我们用Ctrl+C就无法终止前台的进程。只有使用kill -9 目标进程pid,才能杀掉后台进程。

        一般而言,进程收到信号的处理方案有3中情况

1.默认动作-- 一部分是终止自己,暂停等

2.忽略动作--是一种信号处理的方式,只不过动作就是什么也不干

3.(信号的捕捉)自定义动作--我们刚刚用signal方法,就是在修改信号的处理动作由:默认-〉自定义动作

——9号信号无法被自定义(捕捉)


3.进程异常/崩溃的原理

(1).进程为什么会崩溃?

        在win or Linux下进程崩溃的本质,是进程收到了对应的信号,然后进程执行信号的默认处理动作(杀死进程)

        根本原因:你的操作影响到了硬件或者其他软件,操作系统检测到了,就发送对应的信号终止了进程。

        所有的异常都是操作系统给进程发送信号导致的。自定义异常就很像自定义信号处理。

1.出现段错误(segmentation fault)

原因:访问越界或者使用野指针(实际上也是访问越界)

野指针的情况:

1.指针没有被初始化

2.指针指向的空间被释放,指针没有置空

3.指针变量进行了错误的运算

4.进行了错误的指针类型转换

为什么会崩溃,因为收到了11号信号 SIGSEGV seg fault

2.浮点数异常(除0错误),实际上是因为发送了8号信号 SIGFPE float point e

(2).如何知道进程崩溃/异常的原因

        进程崩溃/异常退出的时候,进程会收到信号,我们waitpid得到的status里面。低7位就是终止信号,我们可以根据终止信号来判断进程崩溃的原因


(3).core dump的作用——可以知道在哪一行崩溃的

core dump——核心转储

        除此之外,进程如果异常的时候,使用了core dump的话,该位置会被设置为1

        注:进程异常终止的时候,不一定所有的信号都会产生core dump文件(由core dump这一位决定),但是低7位的终止信号肯定会被设置

可以用以下方式检验:用位运算哪一位都可以给你取出来

  printf("exit code: %d, exit sig: %d, core dump flag: %d\n", (status>>8)&0xFF, status&0x7F, (status>>7) & 1);
  1. 在Linux中,当一个进程退出的时候,它的退出码和退出信号都会被设置(正常情况)
  2. 当一个进程异常的时候,进程的退出信号会被设置,表明当前进程退出的原因
  3. 如果必要,OS会设置退出信息中的core dump标志位为1,并将进程在内存中的数据转储到磁盘当中,方便我们后期调试

         在一般的云服务器中,core dump的相关功能默认是关闭的,我们可以使用以下指令打开这个功能:

ulimit -c 10240

        打开以后,我们在运行可执行文件的时候,后面会跟上core dumped,表示当前进程文件被core dumped了,而且在当前目录下会多一个文件,也就是内存中的一些数据,保存了出现异常时的一些数据,比如是在哪一行代码出现的异常。

        此时我们对要调试的可执行文件进行调试,进入调试模式后,可以使用core-file命令把core文件加载进来,此时我们可以知道代码崩溃在哪一行。这就是事后调试。        


4.信号的产生方式

1. 键盘产生(比如Ctrl+C发出2号信号,只能对前台进程发信号)

2. 进程异常,也能产生信号(本质上是因为比如I/0异常,非法访问等异常会导致硬件异常,见上节)

3. 通过系统调用,产生信号(比如kill指令或者kill函数)

4. 软件条件,也能产生信号

        信号产生的方式种类虽然非常多,但是无论产生信号的方式千差万别,但是最终,一定都是通过OS向目标进程发送的信号

系统调用产生信号(kill,raise,abort函数)

        采用系统调用向目标进程发起信号,在代码里面可以调用kill函数

 kill函数:采用系统调用向目标进程发起信号

 raise函数(C库中的函数):自己给自己发信号

 

 kill和raise函数都是成功返回0,失败返回-1

abort函数:给自己发一个6号信号

就像exit函数一样,abort函数总是会成功的,所以没有返回值。


软件条件产生信号(alarm函数)

        通过某种软件(OS),来触发信号的发送,系统层面设置定时器,或者某种操作而导致条件不就绪等这样的场景下,触发的信号发送。

        e.g.:进程间通信:当读端不光不读,而且还关闭了读fd,写端一直在写,最终写进程会受到sigpipe (13),就是一种典型的软件条件触发的信号发送

alarm函数:

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

        这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数

        alarm(0)表示关闭闹钟,返回值就是剩余的秒数

e.g.:尝试统计如果count每次加1,服务器1秒钟能把count加到多少

alarm.test:

#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
int count = 0;
void handler(int signo)
//自定义函数,发送SIGALRM信号以后,先打印count的值,然后再调用exit函数退出进程
{
    cout << "count: " << count << endl;
    exit(1);
}

int main()
{
    signal(SIGALRM,handler);
    alarm(1);
    while(true)
    {
        count++;
        // cout << "count: " << count << endl;
    }
    return 0;
}

如果每一次循环都将count的值打印一遍,则可以加到9万多 

 

        如果每次循环不打印,等到1s过后,当对SIGALRM14号信号进行处理的时候再打印,则可以加到更大的数,原因是因为IO太慢了,除了打印的是IO,服务器和主机交互的网络通信也算是IO,所以不要每次循环都打印的话,可以有更多的时间给到CPU去计算。

 

 

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

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

相关文章

C++类设计和实现的十大最佳实践

C代码提供了足够的灵活性&#xff0c;因此对于大部分工程师来说都很难把握。本文介绍了写好C代码需要遵循的10个最佳实践&#xff0c;并在最后提供了一个工具可以帮助我们分析C代码的健壮度。原文&#xff1a;10 Best practices to design and implement a C class 1. 尽可能尝…

Word处理控件Aspose.Words功能演示:使用 C# 将 Word 文档转换为 HTML

在各种情况下&#xff0c;您需要在 Web 或桌面应用程序中显示 Word 文档的内容。在这种情况下&#xff0c;合适的选项之一是将 Word 文档转换为HTML。为了在 .NET 应用程序中实现这一点&#xff0c;本文介绍了如何使用 C# 将 Word DOCX或DOC文件转换为 HTML。此外&#xff0c;您…

搅拌釜反应器全自动真空压力(正负压)控制解决方案

摘要&#xff1a;针对双层玻璃反应釜中存在的无法进行真空压力自动和准确控制等问题&#xff0c;本文提出了完整和成熟的解决方案&#xff0c;即采用卫生级电动调节阀和高精度双通道PID控制器&#xff0c;结合不同量程的真空计&#xff0c;与反应器、真空泵和正压气源构成闭环控…

ARP协议与ARP欺骗

一、ARP协议&#xff08;地址解析协议&#xff09; 所谓“地址解析”就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程,ARP协议的基本功能就是通过目标设备的IP地址&#xff0c;查询目标设备的MAC地址&#xff0c;以保证通信的顺利进行。 将一个已知的IP地址解析为MAC…

169. 基于Django-RESTFramework的节流的使用

1.节流概述 节流又称限流&#xff0c;限制访问。 就是一个用户多次发送一个请求&#xff08;页面或者链接&#xff09;的时候&#xff0c;单位时间允许访问次数限制&#xff0c;超过限制就会出现访问受限&#xff0c;提示譬如&#xff1a;离下一场访问还有多久之类等的字样。 …

基于SSM的学生考勤管理系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

【学习笔记】顺序容器的表格方式总结 C++

目录顺序容器及其特点顺序容器操作向顺序容器添加元素insertemplace参考更新中… 顺序容器及其特点 名字访问元素插入&#xff0c;删除元素vector&#xff08;可变大小数组&#xff09;支持快速随机访问在尾部之外的位置插入或删除元素可能很慢deque&#xff08;双端队列&…

SpringBoot实战:整合MapStruct实现数据类型转化

MapStruct 是一个代码生成器&#xff0c;它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用&#xff0c;因此速度快、类型安全而且易于理解阅读&#xff1b;本篇就是实现 SpringBoot 整合 MapStruct 实现数据类型…

[附源码]JAVA毕业设计小区物业管理系统演示录像2020(系统+LW)

[附源码]JAVA毕业设计小区物业管理系统演示录像2020&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09…

ffmpeg库安装及入门指南(Windows篇)- 2022年底钜献

最近项目需要&#xff0c;使用了 ffmpeg 做摄像头视频采集和串流。这几天有点时间&#xff0c;打算把相关的一些知识记录分享一下。 在撰写本文时&#xff0c;我又在另外一台电脑上把 ffmpeg 重新安装了一遍&#xff0c;所以绝对真实靠谱&#xff01;如果你觉得文章写得还不错…

代码效果测试

ROBUST TEXT DETECTION IN NATURAL IMAGES WITH EDGE ENHANCED MAXIMALLY STABLE EXTREMAL REGIONS 代码地址&#xff1a;https://github.com/akab/TextDetection 基本步骤&#xff1a; 1&#xff09;将原图转为灰度图&#xff1b; 2&#xff09;使用OpenCV的canny函数进行边…

HTML -- 常用标签及示例总结

文章目录HTML常用标签1 标签语义1.1 标签属性2 标题标签 h1 - h63 段落和换行标签3.1 段落标签3.2 换行标签4 文本格式化标签5 div和span6 图像标签7 超链接标签7.1 链接的语法格式7.2 链接分类8 表格标签8.1 表格的主要作用8.2 表格的基本语法8.3 表头单元格标签8.4 表格属性8…

C语言随机数的产生(rand、srand、time函数细节讲解)

✨C语言随机数的产生随机数生成代码&#xff1a;rand函数&#xff1a;srand函数&#xff1a;time函数&#xff1a;time函数补充:time_t类型讨论time_t指针传入的讨论&#xff1a;随机数生成代码&#xff1a; 先上代码&#xff0c;再详细解释&#xff1a; #include<stdio.h…

Python数组数据处理办法清单

import numpy as np import pandas as pd import matplotlib.pyplot as plt#matplotlib 的字体&#xff08;font&#xff09;为黑体&#xff08;SimHei&#xff09; plt.rcParams[font.sans-serif] [SimHei, ] # matplotlib正确显示正负号 plt.rcParams[axes.unicode_minus] …

dfs序(树形结构线性化)

dfs序是将树形结构转换为线性结构的一种方式。 dfs序 dfs序&#xff1a; 指每个节点在dfs深度优先遍历中的进出栈的时间序列。 定义三个数组&#xff1a; in[x]&#xff1a;表示结点x 入栈的时间戳。 out[x]&#xff1a;表示结点x出栈的时间戳&#xff0c;特殊的&#xff0c;出…

Linux网络原理及编程(5)——第十五节 TCP的连接(三次握手、四次挥手)

目录 三次握手 四次挥手 我们来重点说说两个状态&#xff1a;CLOSE_WAIT和TIME_WAIT 【CLOSE_WAIT】 【TIME_WAIT】 各位好&#xff0c;博主新建了个公众号《自学编程村》&#xff0c;拉到底部即可看到&#xff0c;有情趣可以关注看看哈哈&#xff0c;关注后还可以加博主w…

Linux CENTOS安装mysql8 64位

1. 查看系统中是否已经安装了mariadb 执行&#xff1a;yum list installed | grep mariadb 若已经存在&#xff0c;则删除 执行&#xff1a; yum remove mariadb 2.下载需要安装的压缩文件&#xff0c;从官网下载&#xff0c;文件为名字为 mysql-8.0.31-linux-glibc2.12-x86_6…

S7-1200和1500PLC与条码枪建立TCP_IP通信的具体方法示例

S7-1200和1500PLC与条码枪建立TCP_IP通信的具体方法示例 今天和大家分享西门子S7-1200和1500PLC如何获取条码枪的扫描数据,这种案例中一般PLC作为TCP/IP的客户端(只接收数据,不发送数据),条码枪作为TCP/IP的服务器。 如下图所示,在指令—通信—开放式用户通信中可以找到相关…

洞察 | 软件定义汽车时代下,汽车制造产业的应对策略

汽车产业作为先进制造行业&#xff0c;伴随着数字化技术&#xff0c;电气化技术的迭代正快速的成长&#xff0c;而随着智能汽车、自动驾驶概念的提出&#xff0c;整车制造的软硬件复杂度也在持续提升&#xff0c;软件定义汽车转型已成整体汽车制造产业的共识。 据中国软件行业…

成长任务| 挑战代码画颗圣诞树

&#x1f384;立即投稿&#x1f384; &#x1f4cc;活动规则 圣诞将至&#xff0c;这次来试试用代码过圣诞吧~挑战圣诞树的一万种画法! √ 使用代码画一颗#圣诞树#&#xff0c;将你的代码文件通过本页面投稿&#xff0c;审核通过即可参与活动 √ 可使用任意编程语言&#xff…