Linux信号机制探析--信号的产生

2024-08-22 03:52

本文主要是介绍Linux信号机制探析--信号的产生,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🍑个人主页:Jupiter.
🚀 所属专栏:Linux从入门到进阶
欢迎大家点赞收藏评论😊

在这里插入图片描述

在这里插入图片描述

目录

  • `📚信号`
            • `什么是信号?`
            • `为什么要有信号?`
            • 查看Linux系统中信号
    • `🎈信号产生`
      • `📕kill 命令产生信号`
      • `🏠键盘产生 `
      • `🦅系统调用`
            • kill系统调用
            • raise系统调用
            • abort系统调用
      • `🍑软件条件`
      • `🌠硬件异常产生信号`
        • 对于键盘产生信号的理解
        • 对硬件异常产生信号的理解
            • 为什么默认的是core dump(核心转储)功能是关闭的呢


📚信号

什么是信号?
  • 信号是Linux系统提供的让进程或则操作系统给其他进程发送异步信息的一种方式。

  • 信号的产生是随时产生的,进程无法预料,所以信号是异步发送的。(信号的产生是由别的进程产生的,在收到信号之前,我(进程)在做自己的事情,我和发送信号的进程是在并发跑的。所以是异步)

为什么要有信号?
  • Linux系统中要有信号,主要是为了提供一种机制,以便异步地处理系统事件和进程间通信。

    • 进程间通信:信号是进程间通信(IPC)的一种方式,允许进程之间异步地传递消息。
    • 系统事件通知:操作系统可以使用信号来通知进程发生了系统级事件,如非法内存访问(段错误)、软件终止请求(如用户按下Ctrl+C)等。
    • 简化编程模型:信号提供了一种机制,允许操作系统和应用程序开发者以一种标准化的方式处理各种异步事件,从而简化了编程模型。
    • 资源管理:信号可以用于管理进程占用的资源。例如,当进程占用的资源超出限制时,系统可以发送信号来终止或暂停该进程。
    • 用户交互:用户可以通过发送信号来控制进程的行为,例如,使用kill命令发送信号以终止或暂停进程。
    • 错误处理:当进程执行非法操作时,系统可以发送信号来通知进程发生了错误,进程可以根据信号的指示进行错误处理。
查看Linux系统中信号
  • kill -l命令可以查看系统定义的信号列表:
  • 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定义 #define SIGINT 2
  • 编号34以上的是实时信号,本章只讨论编号34以下的信号,不讨论实时信号。这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal
  • 注意:没有0 ,32 ,33号信号

🎈信号产生

📕kill 命令产生信号

  • 如:杀掉指定进程: kill -9 进程编号

🏠键盘产生

  • 如:2号信号 :ctrl + c 可以终止进程 3号信号:ctrl + \ 终止进程
  • 会将该组合键解释为信号 --> 向目标进程发送该信号 —> 进程收到信号 —> 响应信号。

🦅系统调用

kill系统调用

函数介绍:

  • 功能: 向任意的进程发送任意的信号。

  • 参数:参数一:进程pid ; 参数二:信号编号或则信号名称。

  • 返回值: 0表示成功,-1表示失败。

示例代码:

void handler(int signo)
{cout << "receive a signal: " << signo << endl;
}
int main()
{signal(2,handler);int n = kill(getpid(),2);  //给自己发送2号信号return 0;
}

运行结果预期:使用kill系统调用给自己发送一个2号信号,2号信号被捕捉,当收到二号信号的时候,执行我们写的handler函数,打印信息 :receive a signal:2

运行结果:
在这里插入图片描述

raise系统调用

函数介绍:

  • 功能:谁调用,就向哪一个进程发送任意信号

  • 参数:信号编号/信号名称

  • 返回值:0表示成功,非0表示失败。

代码示例:

void handler(int signo)
{cout << "receive a signal: " << signo << endl;
}int main()
{signal(2,handler);int n  = raise(2);return 0;
}

运行结果:
在这里插入图片描述

abort系统调用

函数介绍:

  • 功能:向调用该函数的进程发送6号信号:SIGABRT(终止进程)。

示例代码:

int main()
{int cnt = 1;while(cnt++){if(cnt == 5){abort();}cout<<"i am a process,pid:"<<getpid()<<endl;}return 0;
}

运行结果:
在这里插入图片描述

🍑软件条件

SIGPIPE是一种由软件条件产生的信号(管道的读端不读,还关闭了读文件描述符,则写端就会因为写条件不具备而被OS终止,OS给写端进程发送的信号就是SIGPIPE:13号信号)。本节还介绍alarm函数SIGALRM信号

函数介绍:

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

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。比如:当我们设定一个50秒的闹钟,如果在20秒的时候,提前给该进程发送一个SIGALRM信号使进程提前响应,这时,返回值就为50-20=30。

alarm(0):取消闹钟

示例代码:

int main()
{alarm(5);while(true){cout<<"i am a process,pid:"<<getpid()<<endl;sleep(1);}return 0;
}

运行结果:
在这里插入图片描述

对SIGALRM信号进行捕捉,实现2秒循环的闹钟
代码实现:

void handler(int signo){cout << "receive a signal: " << signo << endl;alarm(2);
}
int main()
{signal(SIGALRM,handler);alarm(2);while(true){cout<<"i am a process,pid:"<<getpid()<<endl;sleep(1);}return 0;
}

运行结果:
在这里插入图片描述

🌠硬件异常产生信号

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

  • 例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。
  • 再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

除0异常示例代码:

int main()
{int a = 0;int b = 4/0;while(true){}sleep(1);return 0;
}

运行结果:
在这里插入图片描述

访问空指针示例代码:

int main()
{int *p = 0;*p=10;return 0;
}

运行结果:
在这里插入图片描述

对于键盘产生信号的理解

字符输入(字符设备),组合键输入(输入的命令),对于键盘来说,输入的一律当成字符处理,至于到底是字符还是命令,是需要OS键盘驱动来联合解释的。

OS怎么知道键盘在输入数据?(简略介绍)

  • 使用了一种硬件中断的技术。
  • 在开机的时候,OS已经形成了一张中断向量表(函数指针数组),这张表可以提前注册很多对软硬件操作的方法,比如下面表中2号位置是从键盘中读取数据,CPU底部由很多的针脚与外设相连接,这些针脚都有自己的编号当OS正在执行常规代码得时候,用户按键盘输入数据得时候,会给CPU上的特定针脚触发特定的硬件中端,CPU就会将该针脚编号放到一个寄存器中,这时候硬件到软件的动作就完成了,然后CPU就会要求OS停止当前正在执行的工作,让OS根据中端号,取中端向量表中查找对应的操作方法,然后去执行读取键盘数据的任务。
    在这里插入图片描述

通过上面的操作后,已经读取到了数据了,接下来会对读取的数据进行判定

如果操作系统判定为是一般字符输入,则直接放到键盘缓冲区中,如果判定为控制命令OS则会将控制命令解释成信号,然后将信号发送给进程

对硬件异常产生信号的理解
  • 除0错误问题

    首先,计算均在CPU中进行的,对于除0错误的计算过程中,会将标志寄存器中的溢出位的0置为1,将计算错误表现到CPU的寄存器上(硬件上),然后CPU发现硬件出现异常,这时OS会介入,发现问题后,将对应的信号发送给相应的进程。

  • 野指针问题

    CPU有一个硬件MMU,专门负责虚拟地址到物理地址的转换,同时又两个寄存器,CR2与CR3,如果虚拟地址转换成功,会将转换好的物理地址放到CR3中,如果转换出错,则会将错误标志信息放到CR2中,当野指针的时候,首先将野指针地址放到一个寄存器中,然后通过MMU进行转换,在转换的过程中,发现页表中没有这个虚拟地址或则该虚拟地址中没有相应的权限,则会转换出错,将错误标记放在CR2中,表明了CR2出异常,硬件出现异常,这时OS会介入,发现问题后,将对应的信号发送给相应的进程。
    在这里插入图片描述
    一个进程,出现异常大多都是将进程终止,但是man 7 signal 中,终止又两种,一个Term,一个是Core,他们有什么区别呢?以及之前在讲进程的时候,进程等待的status位图core dump标记位和这个Core的关系。
    在这里插入图片描述
    在这里插入图片描述

Core Dump

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

  • 查看core是否打开 指令:ulimit -a
    在这里插入图片描述

  • 开启Linuxcore dump功能:用ulimit命令改变这个限制,允许产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: $ ulimit -c 1024
    在这里插入图片描述
    打开过后,再运行一个除0错误的程序,会再当前工作目录中形成一个core文件(ubuntu系统),文件的名字在不同的平台不同(centos系统中就是以core.进程编号命名的)。

事后调试

gdb 可执行程序 —>core-file core 就会将相关调试信息列出(比如,在哪一行出错,出什么错)。

为什么默认的是core dump(核心转储)功能是关闭的呢
  • 有一些平台的core命名不同,如果每一个进程出现core dump后,都形成不同的core文件,那么很容将服务器的磁盘打满。

这篇关于Linux信号机制探析--信号的产生的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1095166

相关文章

Linux下修改hostname的三种实现方式

《Linux下修改hostname的三种实现方式》:本文主要介绍Linux下修改hostname的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下修改ho编程stname三种方式方法1:修改配置文件方法2:hFvEWEostnamectl命

Linux虚拟机不显示IP地址的解决方法(亲测有效)

《Linux虚拟机不显示IP地址的解决方法(亲测有效)》本文主要介绍了通过VMware新装的Linux系统没有IP地址的解决方法,主要步骤包括:关闭虚拟机、打开VM虚拟网络编辑器、还原VMnet8或修... 目录前言步骤0.问题情况1.关闭虚拟机2.China编程打开VM虚拟网络编辑器3.1 方法一:点击还原VM

Linux搭建Mysql主从同步的教程

《Linux搭建Mysql主从同步的教程》:本文主要介绍Linux搭建Mysql主从同步的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux搭建mysql主从同步1.启动mysql服务2.修改Mysql主库配置文件/etc/my.cnf3.重启主库my

Linux系统之authconfig命令的使用解读

《Linux系统之authconfig命令的使用解读》authconfig是一个用于配置Linux系统身份验证和账户管理设置的命令行工具,主要用于RedHat系列的Linux发行版,它提供了一系列选项... 目录linux authconfig命令的使用基本语法常用选项示例总结Linux authconfi

jdk21下载、安装详细教程(Windows、Linux、macOS)

《jdk21下载、安装详细教程(Windows、Linux、macOS)》本文介绍了OpenJDK21的下载地址和安装步骤,包括Windows、Linux和macOS平台,下载后解压并设置环境变量,最... 目录1、官网2、下载openjdk3、安装4、验证1、官网官网地址:OpenJDK下载地址:Ar

linux本机进程间通信之UDS详解

《linux本机进程间通信之UDS详解》文章介绍了Unix域套接字(UDS)的使用方法,这是一种在同一台主机上不同进程间通信的方式,UDS支持三种套接字类型:SOCK_STREAM、SOCK_DGRA... 目录基础概念本机进程间通信socket实现AF_INET数据收发示意图AF_Unix数据收发流程图A

linux环境openssl、openssh升级流程

《linux环境openssl、openssh升级流程》该文章详细介绍了在Ubuntu22.04系统上升级OpenSSL和OpenSSH的方法,首先,升级OpenSSL的步骤包括下载最新版本、安装编译... 目录一.升级openssl1.官网下载最新版openssl2.安装编译环境3.下载后解压安装4.备份

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst

linux打包解压命令方式

《linux打包解压命令方式》文章介绍了Linux系统中常用的打包和解压命令,包括tar和zip,使用tar命令可以创建和解压tar格式的归档文件,使用zip命令可以创建和解压zip格式的压缩文件,每... 目录Lijavascriptnux 打包和解压命令打包命令解压命令总结linux 打包和解压命令打

linux如何复制文件夹并重命名

《linux如何复制文件夹并重命名》在Linux系统中,复制文件夹并重命名可以通过使用“cp”和“mv”命令来实现,使用“cp-r”命令可以递归复制整个文件夹及其子文件夹和文件,而使用“mv”命令可以... 目录linux复制文件夹并重命名我们需要使用“cp”命令来复制文件夹我们还可以结合使用“mv”命令总