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

第五部分:3---信号的介绍、产生、保存、处理

目录

信号的概念:

异步的概念:

信号的3种处理方式:

修改2号信号为自定义信号处理:

​编辑

信号捕捉后恢复和信号的忽略:

信号的分类与编号:

特殊的信号:

进程信号表的继承:

进程管理收到的普通信号:

系统调用kill向进程发送信号:

系统调用raise向自己发送信号:

系统调用abort向自己发送6号信号:

信号的产生方式:

异常产生信号:

发送信号的本质:


信号的概念:

  • 信号是进程间通信的一种异步通知机制,用于向目标进程发送通知。

  • 信号的处理是异步的,意味着信号可以在任何时候产生,而进程会在适当时机对信号作出处理。

异步的概念:

  • 异步(Asynchronous)是指在编程或系统设计中,任务的执行不需要立即等待其他任务完成,而是可以在不阻塞的情况下继续进行。

信号的3种处理方式:

  • 信号有三种处理方式:默认处理,忽略,自定义处理(捕捉)。

  • 信号的捕捉,就是对信号设置自定义信号函数,signal函数会直接修改信号表中对应信号的处理函数指针,使其指向自定义信号处理函数。

#include<signal.h> //signal函数使用需要包含的头文件
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

修改2号信号为自定义信号处理:

#include<iostream> 
#include<unistd.h> //使用sleep
#include<signal.h> //使用signal
#include<cstdlib> //使用exit
using namespace std;
​
void signalHandle(int signum) //返回值必须为void,参数必须为int
{
    cout<<"收到信号"<<signum<<endl;
    exit(1);
}
​
int main()
{
    signal(2,signalHandle); //将2号信号设置自定义处理函数
    while(true)
    {
        cout<<"等待接收信号..."<<endl;
        sleep(1);
    }
    return 0;
}

信号捕捉后恢复和信号的忽略:

signal(int signum,SIG_IGN); //SIG_IGN:忽略该信号。
signal(int signum,SIG_DFL); //SIG_DFL:恢复为信号的默认处理方法(之前设置的处理函数将作废)。

信号的分类与编号:

  • 信号分为两类:普通信号(1~31)和实时信号(34~64)。

  • 信号以宏的方式实现,使用信号可以通过信号的宏名也可以通过信号的值。

  • 使用 kill -l 可以查看当前系统支持的所有信号。

  • 使用man 7 signal查看信号详细介绍。

特殊的信号:

  • 没有 0 号信号,0 常用于表示进程的正常退出。

  • 32 和 33 号信号是为操作系统内部保留的,用户进程不会使用这些信号。

  • 9 号信号 (SIGKILL) 不能被进程捕获或忽略,称为“管理员信号”,确保进程可以被强制终止。

进程信号表的继承:

  • 每个进程都有一张信号表,本质是一个函数指针数组,数组的下标就对应每一个信号的编号。

  • 当使用fork()系统调用创建子进程时,子进程会复制父进程的信号处理表。这意味着父进程如何处理信号,子进程刚被创建时也会如何处理信号。

  • 当一个进程通过 exec() 系列函数进程程序替换时,信号表中的自定义处理方式会恢复为默认处理方式(操作系统定义的默认行为)。

进程管理收到的普通信号:

  • 进程收到某个信号,操作系统不会立即中断进程的执行,而是先记录该信号。当进程进入内核态时,操作系统会检查是否有待处理的信号,并根据优先级和进程的状态决定何时处理这些信号。

  • 操作系统会使用一个位图来表示进程接收到的信号状态。位图中的每一位对应一个信号编号,通常信号编号从1开始。因此位图第0位是不用的。当对应位置为1时表示进程收到该信号,为0时表示进程没有收到对应信号。

  • 位图的比特位数需要覆盖所有可能的信号。现代Linux系统中支持的信号通常远超过32个,所以可能需要使用多个uint32_t或更大的数据结构(如sigset_t)来存储信号。

系统调用kill向进程发送信号:

#include <signal.h> //头文件包含
int kill(pid_t pid, int sig); //向pid进程发送sig信号

系统调用raise向自己发送信号:

#include <signal.h>  //头文件包含
int raise(int sig); //向自己发送sig信号,相当于kill(getpid(),sig);

系统调用abort向自己发送6号信号:

#include <stdlib.h> 
void abort(void); //给自身发送6号信号强终止自己,即使使用signal重写了信号的处理方法,进程也会被强制结束。

信号的产生方式:

  • 信号的产生方式主要有三种:

  • 在linux下,通过特殊的键盘组合键可以产生信号,如上

  • 通过一些系统调用可以产生信号。如上

  • 程序运行过程中,某些程序异常会自动产生异常信号,如下

异常产生信号:

  • 非法访问内存:当程序试图访问无效的内存地址时,会产生 SIGSEGV 信号(分段错误)。

  • 浮点运算异常:当程序发生非法的浮点运算(如除以零)时,会产生 SIGFPE 信号。

  • 非法指令:当程序试图执行非法或未知的指令时,会产生 SIGILL 信号。

  • 总线错误:当程序发生不对齐的内存访问等硬件错误时,会产生 SIGBUS 信号。

  • 断管(Broken Pipe):当进程向一个没有读取端的管道写入数据时,会产生 SIGPIPE 信号。

发送信号的本质:

  • 操作系统向进程发送信号,本质上是操作系统修改进程pcb的位图。

  • 只有操作系统可以向进程发送信号,因为操作系统才是内核数据结构的管理者。

  • 因此,上述产生信号的方式虽然有几种,但是信号的发送者只能是操作系统。


http://www.kler.cn/a/322313.html

相关文章:

  • PH热榜 | 2024-11-19
  • 闫氏DP分析法应用
  • Java 全栈知识体系
  • oracle19c开机自启动
  • 【AlphaFold3】开源本地的安装及使用
  • HarmonyOS 如何获取设备信息(系统、版本、网络连接状态)
  • Ks渲染做汽车动画吗?汽车本地渲染与云渲染成本分析
  • 【Android】布局优化—include,merge,ViewStub的使用方法
  • uniapp小程序中通过uni.setClipboardData实现复制功能无效的原因和解决方案
  • Android中为文本添加下划线、删除线、加粗效果
  • “核问”智能问答系统,引领核工业数据驱动未来
  • 宝塔面板部署雷池社区版教程
  • 【Python基础(一)】
  • Total Blocking Time指标
  • TinyWebSever项目面试题整理
  • OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【Trace调测】
  • 三大硬核方式揭秘:Java如何与底层硬件和工业设备轻松通信!
  • EE trade:黄金T+D是什么意思
  • 【系统架构设计师】专题:软件架构概述
  • 银河麒麟桌面操作系统如何添加WPS字体
  • pyqt瀑布流布局
  • java提升-常见的java调试工具介绍
  • 在 Kubernetes 上部署 .NET 应用的完整指南:从容器化到自动化 CI/CD
  • 【深度学习】03-神经网络01-4 神经网络的pytorch搭建和参数计算
  • BiGRU——提高基于 RNN免疫反应预测的准确性
  • 矩阵学习过程中的一些思考