当前位置: 首页 > news >正文

Linux 信号的产生

1. 概念

在Linux系统中,信号是一种进程间通信的机制,它允许操作系统或其他进程向特定进程发送异步通知。我们可以通过命令 kill -l来查看信号的种类:

Linux系统中的信号可以分为两大类:传统信号和实时信号。从上图可以看出它们分为两个区间:[1, 31] 和[34, 64],无32和33号信号,[1, 31] 区间为传统信号共有31种,当进程收到传统信号后,可以自己选择合适的时候处理;[34, 64]为实时信号共有31种,当进程收到实时信号后,立马处理。

以下是一些常见信号的简要说明:

  • SIGINT(2):用户通过Ctrl+C发送的中断信号,通常用于请求进程终止。
  • SIGQUIT(3):用户通过Ctrl+\发送的退出信号,通常用于请求进程终止并生成core dump。
  • SIGABRT(6):通过调用abort()函数产生的信号,用于异常终止程序。
  • SIGFPE(8):发生致命的算术运算错误时产生。
  • SIGKILL(9):用于立即强制终止进程的信号,不能被进程捕获、阻塞或忽略。
  • SIGSEGV(11):试图写入无效内存地址时产生。
  • SIGALRM(14):由alarm()函数设置的计时器到期时产生。
  • SIGSTOP(19):停止进程执行的信号,不能被进程捕获、阻塞或忽略。
  • SIGTSTP(20):由用户通过Ctrl+Z发送的暂停信号,可以被进程捕获和处理。

进程接收到信号后,有三种处理信号的方式:

  1. 忽略此信号
  2. 执行信号的默认处理函数
  3. 执行信号的自定义处理函数,这种方式也称为信号捕捉

前两种均为操作系统自带的方式,我们可以通过 man 7 signal 命令来查看这些处理行为:

  1. Term (Terminate):这是当一个信号没有被处理(即没有安装信号处理函数)时,信号的默认行为,收到信号的进程将被终止。例如,SIGTERM的默认行为是终止进程。

  2. Ign (Ignore):进程可以选择忽略一个信号,这意味着当信号到达时,进程将不会执行任何默认行为或自定义处理函数。

  3. Core:指的是在进程终止时生成core dump的行为。当进程因为某些信号(如SIGSEGV)而终止时,如果设置了对应的信号行为为core,系统将生成该进程在终止瞬间的内存快照,以便于后续的错误分析。

  4. Stop:指的是信号的默认行为或自定义动作是停止进程的执行。例如,SIGSTOP信号会使进程停止,且不能被进程捕获或忽略。其他可停止信号(如SIGTSTP)可以被进程捕获和处理。

  5. Cont (Continue):指当一个已停止的进程接收到继续信号(如SIGCONT)时,将恢复执行。进程从停止状态恢复到运行状态。

我们继续往下翻可以看到各种信号对应的默认行为。

接下来我们来介绍第三种信号处理的方式,即信号捕捉。需要使用到 signal 函数。signal 函数是C语言标准库中的一个函数,用于设置信号处理程序,当程序运行时接收到特定的信号,signal 函数允许开发者定义一个函数来响应这些信号。

其中,signum参数指定了要处理的信号编号,handler参数是一个指向信号处理函数的指针,该函数指针类型为 void (*)(int)。如果 handlerSIG_IGN,则信号将被忽略;如果为 SIG_DFL,则信号将采用默认的操作系统行为。

#include<iostream>
#include<signal.h>
using namespace std;
void handler(int signum)
{cout<<"received signal: "<<signum<< endl;
}
int main()
{signal(2,handler);while(1){cout<<"waiting for signal..."<<endl;sleep(1);}return 0;
}

以上代码中,我们通过 signal(2, handler) 把2号信号的处理方式变成了执行函数handler。而从上文介绍我们了解到从键盘上按下 ctrl + C 可以发送2号SIGINT信号。

可以看到按下ctrl + C后,本来是发送2号信号时会直接终止进程,但修改处理行为后,现在输出receive signal: 2了。

3. 注意
1. ctrl +  C  产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行 , 这样 Shell 不必等待进程结束就可以接受新的命令, 启动新的进程。
2. Shell 可以同时运行一个前台进程和任意多个后台进程 , 只有前台进程才能接到像 ctrl +  C 这种控制键产生的信号。
3. 前台进程在运行过程中用户随时可能按下 Ctrl - C 而产生一个信号 , 也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止 , 所以信号相对于进程的控制流程来说是异步
(Asynchronous) 的。

2. 产生

信号可以由多种方式产生,包括硬件产生和软件产生。

软件产生

软件产生的信号指的是由进程自身或其他进程产生的信号,其可以通过系统调用实现,常用的系统调用包括 kill()raise()abort()alarm()

kill

kill函数是在Unix和类Unix系统中,包括Linux,用于向进程发送信号的系统调用。这个函数允许一个进程请求操作系统向另一个进程发送指定的信号,从而可以控制目标进程的行为,如终止进程、请求进程停止或继续执行等。

参数:

  • pid:目标进程的进程ID。如果pid为正数,则信号发送给指定的进程;如果pid为0,则信号发送给调用进程所属的进程组。
  • sig:准备发送的信号码。如果sig为0,则不发送信号,但会执行错误检查,通常用于检测目标进程是否存在。

返回值:

  • 返回0:发送信号成功
  • 返回-1:发送信号失败

void handler(int signum)
{cout<<"received signal: "<<signum<< endl;exit(1);
}
int main()
{pid_t pid = fork();if(pid == 0)//child{signal(2,handler);while(1){cout<<"child process waiting for signal..."<<endl;sleep(1);}}sleep(5);kill(pid,2);//send signal to child processreturn 0;
}

代码示例如上,子进程等待信号,5秒后,父进程向子进程发出2号信号,子进程收到该信号并执行handler 函数,最终退出。

同时,我们也可以在 Shell 中使用 kill 命令,如下,其底层为调用 kill接口。

kill -sig pid

raise

参数:

  • sig:要发送的信号的编号

返回值:

  • 返回0:发送信号成功
  • 返回-1:发送信号失败

在Linux系统编程中,raise函数用于给当前进程发送一个信号,这个函数等效于kill(getpid(), sig)raise函数通常用于引发特定的信号处理程序,或者在需要立即响应信号的场景中使用。

void handler(int signum)
{cout << "received signal: " << signum << endl;exit(1);
}
int main()
{signal(2, handler);int cnt = 5;while (cnt--){cout << "waiting for signal,cnt = " << cnt << endl;sleep(1);}raise(2);return 0;
}

代码示例如上,while 循环执行5秒后,进程给自己发出2号信号,进程收到该信号并执行handler 函数,最终退出。

abort

在Linux系统中,abort函数是一个用于立即终止程序执行的系统调用。它不仅终止程序,而且会生成一个core dump(如果系统配置允许),这有助于调试和理解程序崩溃时的状态。

abort函数被调用时,它会向调用进程发送SIGABRT信号,SIGABRT信号的值通常为6。如果这个信号没有被处理,则默认行为是终止进程并生成core dump,以便后续的错误分析。

core dump的概念

接下来我们来了解 core dump 是什么,core dump 是指当Linux或Unix-like系统中的程序因为异常或错误而崩溃时,操作系统会生成的一个包含了程序崩溃时内存映像的文件。这个文件通常包含了程序的寄存器状态、堆栈信息、内存管理信息等,可以用于调试目的,帮助开发者分析程序崩溃的原因。

代码示例:

int Div(int a, int b)
{if (b == 0)abort();return a / b;
}
int main()
{int a = 5, b = 0;cout << Div(a, b);return 0;
}

上述代码发生了除0错误,进而调用了 abort 函数,可我们并没有看到在当前目录下生成的core dump文件,这是因为生成core dump文件是要有条件的。

core dump文件的生成条件

core dump文件的生成不是自动的,它依赖于几个条件:

  • 当前用户的 ulimit -c+n(单位为byte) 设置必须允许生成core文件,或者设置为 ulimit -c unlimited 以移除大小限制。

  • 程序必须有权限在其当前工作目录中创建文件。

我们可以使用 ulimit -a 命令显示当前的所有资源限制。

我们可以看到 core file size 为 0,即当前我们不能创建core file,我们需要使用ulimit -c 命令设置core file size的大小进而能创建core file。

core dump文件的作用

core dump文件对于软件开发和维护至关重要,因为它们提供了程序崩溃时的详细快照。通过使用调试工具(如GDB)分析​​​​​​​core dump文件,开发者可以追溯程序崩溃时的函数调用堆栈,检查变量的状态,从而定位到导致崩溃的代码行和潜在的错误。

alarm

alarm函数用于设置一个定时器,该定时器会在指定的秒数后向进程发送SIGALRM信号(14)。

参数:

  • seconds:在seconds秒后发送信号

返回值:

  • 如果之前有还没响的闹钟:取消上一次的闹钟,并返回上一次闹钟的剩余秒数
  • 如果之前没有闹钟了:返回0

硬件产生

硬件产生的信号通常是由于用户输入或系统异常触发的。例如,当用户在终端上按下组合键如Ctrl+C时,会产生SIGINT信号,用于中断当前运行的进程。此外,硬件异常,如非法内存访问,也会导致内核生成相应的信号并发送给发生事件的进程。 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 同为TVT设备主动注册协议接入SVMSPro平台
  • 电子看板实时监控数据可视化助力工厂精细化管理
  • 【CTF Reverse】XCTF GFSJ1101 Mine- Writeup(反编译+动态调试+Base58编码)
  • go多线程
  • SysML图例-制药
  • 算法.图论-并查集上
  • 一款全看个人造化的Windows命令行软件下载安装管理器:Scoop
  • Revit学习记录-版本2018【持续补充】
  • python SQLAlchemy 数据库连接池
  • Robot Operating System——32 位浮点数表示的三维空间中一个点
  • 鸿蒙逐渐成为全球操作系统领域的重要一员
  • 为什么 Feign 要用 HTTP 而不是 RPC?
  • DEPLOT: One-shot visual language reasoning by plot-to-table translation论文阅读
  • 【车载以太网】【SOME/IP】Wireshark 解析
  • Google Gemini 与 OpenAI 激烈竞赛:语音 AI 与未来智能体的技术演进
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • [数据结构]链表的实现在PHP中
  • Angular 4.x 动态创建组件
  • CSS 提示工具(Tooltip)
  • isset在php5.6-和php7.0+的一些差异
  • Java超时控制的实现
  • Octave 入门
  • PAT A1092
  • Promise面试题,控制异步流程
  • session共享问题解决方案
  • Shadow DOM 内部构造及如何构建独立组件
  • socket.io+express实现聊天室的思考(三)
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • Xmanager 远程桌面 CentOS 7
  • 基于Android乐音识别(2)
  • 开源地图数据可视化库——mapnik
  • 面试遇到的一些题
  • 微信小程序--------语音识别(前端自己也能玩)
  • 新手搭建网站的主要流程
  • 原生js练习题---第五课
  • 怎么把视频里的音乐提取出来
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • AI算硅基生命吗,为什么?
  • Spring Batch JSON 支持
  • 阿里云服务器如何修改远程端口?
  • ​linux启动进程的方式
  • ‌JavaScript 数据类型转换
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #APPINVENTOR学习记录
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .Net 8.0 新的变化
  • .net core + vue 搭建前后端分离的框架
  • .net core使用ef 6