【在Linux世界中追寻伟大的One Piece】进程信号

目录

[1 -> 信号入门](#1 -> 信号入门)

[1.1 -> 生活角度的信号](#1.1 -> 生活角度的信号)

[1.2 -> 技术应用角度的信号](#1.2 -> 技术应用角度的信号)

[1.3 -> 注意](#1.3 -> 注意)

[2 -> 信号的概念](#2 -> 信号的概念)

[2.1 -> 用kill -l命令可以查看系统定义的信号列表](#2.1 -> 用kill -l命令可以查看系统定义的信号列表)

[2.2 -> 信号处理常见方式](#2.2 -> 信号处理常见方式)

[3 -> 产生信号](#3 -> 产生信号)

[3.1 -> Core Dump](#3.1 -> Core Dump)

[3.2 -> 调用系统函数向进程发信号](#3.2 -> 调用系统函数向进程发信号)

[3.3 -> 由软件条件产生信号](#3.3 -> 由软件条件产生信号)

[3.4 -> 硬件异常产生信号](#3.4 -> 硬件异常产生信号)


1 -> 信号入门

1.1 -> 生活角度的信号

  • 你在网上买了很多件商品,再等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时,你该怎么处理快递。也就是你能"识别快递"。
  • 当快递员到了你楼下,你也收到快递到来的通知,但是你正在打游戏,需5min之后才能去取快递。那么在在这5min之内,你并没有下去去取快递,但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行,可以理解成"在合适的时候去取"。
  • 在收到通知,再到你拿到快递期间,是有一个时间窗口的,在这段时间,你并没有拿到快递,但是你知道有一个快递已经来了。本质上是你"记住了有一个快递要去取"。
  • 当你时间合适,顺利拿到快递之后,就要开始处理快递了。而处理快递一般方式有三种:
    • 执行默认动作(幸福的打开快递,使用商品)。
    • 执行自定义动作(快递是零食,你要送给你的女朋友)。
    • 忽略快递(快递拿上来之后,扔掉床头,继续开一把游戏)。
  • 快递到来的整个过程,对你来讲是异步的,你不能准确断定快递员什么时候给你打电话。

1.2 -> 技术应用角度的信号

  1. 用户输入命令,在Shell下启动一个前台进程。
  • 用户按下Ctrl-C,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程。
  • 前台进程因为收到信号,进而引起进程退出。

[hg@localhost code_test]$ cat sig.c
#include <stdio.h>
int main()
{
while(1){
printf("I am a process, I am waiting signal!\n");
sleep(1);
}
}
[hg@localhost code_test]$ ./sig
I am a process, I am waiting signal!
I am a process, I am waiting signal!
I am a process, I am waiting signal!
^C
[hg@localhost code_test]$

  • 进程就是你,操作系统就是快递员,信号就是快递。

1.3 -> 注意

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

2 -> 信号的概念

信号是用来传递信息的物理量,它可以是电信号、声波、光信号等多种形式。在通信和控制系统中,信号作为信息的载体,通过特定的媒介从发送端传输到接收端。信号可以携带声音、图像、数据等多种类型的信息。

信号是进程之间事件异步通知的一种方式,属于软中断。

2.1 -> 用kill -l命令可以查看系统定义的信号列表

  • 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定义 #define SIGINT 2。
  • 编号34以上的是实时信号,只讨论编号34以下的信号,不讨论实时信号。这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal。

2.2 -> 信号处理常见方式

可选的处理动作有以下三种:

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

3 -> 产生信号

SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump。

3.1 -> Core Dump

首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常是core,这叫做Core Dump。进程异常终止通常是因为有Bug,比如非法内存访问导致段错误,事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug(事后调试)。一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: $ ulimit -c1024。

然后写一个死循环程序。

前台运行这个程序,然后在终端键入Ctrl-C或Ctrl-\:

ulimit命令改变了Shell进程的Resource Limit,test进程的PCB由Shell进程复制而来,所以也具有和Shell进程相同的Resource Limit值,这样就可以产生Core Dump了。

3.2 -> 调用系统函数向进程发信号

首先在后台执行死循环程序,然后用kill命令给它发SIGSEGV信号。

  • 4568是test进程的id。之所以要再次回车才显示Segmentation fault,是因为在4568进程终止掉之前已经回到了Shell提示符等待用户输入下一条命令,Shell不希望Segmentation fault信息和用户的输入交错在一起,所以等用户输入命令之后才显示。
  • 指定发送某种信号的kill命令可以有多种写法,上面的命令还可以写成kill -SIGSEGV 4568或 kill -11 4568, 11是信号SIGSEGV的编号。以往遇 到的段错误都是由非法内存访问产生的,而这个程序本身没错,给它发SIGSEGV也能产生段错误。

kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定的信号(自己给自己发信号)。

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1。

abort函数使当前进程接收到信号而异常终止。

#include <stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值。

3.3 -> 由软件条件产生信号

SIGPIPE是一种由软件条件产生的信号。

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

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。打个比方,某人要小睡一觉,设定闹钟为30分钟之后响,20分钟后被人吵醒了,还想多睡一会儿,于是重新设定闹钟为15分钟之后响,"以前设定的闹钟时间还余下的时间"就是10分钟。如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数。

3.4 -> 硬件异常产生信号

硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。


感谢各位大佬支持!!!

互三啦!!!

相关推荐
无为之士5 分钟前
Linux自动备份Mysql数据库
linux·数据库·mysql
秋名山小桃子15 分钟前
Kunlun 2280服务器(ARM)Raid卡磁盘盘符漂移问题解决
运维·服务器
与君共勉1213816 分钟前
Nginx 负载均衡的实现
运维·服务器·nginx·负载均衡
岑梓铭22 分钟前
(CentOs系统虚拟机)Standalone模式下安装部署“基于Python编写”的Spark框架
linux·python·spark·centos
努力学习的小廉22 分钟前
深入了解Linux —— make和makefile自动化构建工具
linux·服务器·自动化
MZWeiei26 分钟前
Zookeeper基本命令解析
大数据·linux·运维·服务器·zookeeper
7yewh41 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
Arenaschi1 小时前
在Tomcat中部署应用时,如何通过域名访问而不加端口号
运维·服务器
小张认为的测试1 小时前
Linux性能监控命令_nmon 安装与使用以及生成分析Excel图表
linux·服务器·测试工具·自动化·php·excel·压力测试
waicsdn_haha1 小时前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk