【Linux信号】

news2024/11/15 8:27:37

目录

  • 信号是什么
    • Linux通过kill -l查看指令
  • 信号的产生
    • signal系统调用捕捉信号
    • 键盘产生信号
    • 系统调用产生信号
    • 进程异常产生信号
    • 软件条件发送信号
  • Code Dump
  • 信号保存
    • 信号抵达
    • 信号产生到信号抵达之间的状态叫信号未决。
    • 进程可以对信号进行阻塞
      • 使用sigprocmask()系统调用接口阻塞block信号集表
      • sigpending(sigset_t*)检查pending未决信号集
      • 解除信号阻塞
  • 信号的处理时机
  • 信号的捕捉sigaction

信号是什么

如果有一个由C语言编写的无限循环的程序,该进程会一直占据内存一直运行,这个时候再键盘按下Ctrl 和 C一起按,进程就会退出,程序结束。这个Ctrl 和 C的键盘信息就被操作系统识别成一个信号。在Linux中其实是操作系统给进程发送了kill -2的信号。如果一个整形有除0的操作,进程会直接退出,会显示浮点数出错,对一个空指针的解引用,会有段错误。操作系统会给进程分别发送8和11号信号的错误。
进程实际上没有产生信号的时候,就已经知道了每个信号的处理方式,就好比一个人知道交通的红绿灯规则,即使没有看到交通信号等的信号,但已经知道红灯停,绿灯行的规则。
当信号产生到来的时候,进程不一定知道该信号的到了,所以信号对于进程正在工作是异步的,并不同步。就算是知道了,进程也不一定要对他进行处理,就好比绿灯亮了,有的人也不一定要过马路。所以进程一定暂时保存了这些产生的信号。

Linux通过kill -l查看指令

在这里插入图片描述
每种信号对应着不同的数字。

信号的产生

在这里插入图片描述
函数指针数组,都有每个信号的处理方法,所以说每个进程在创建的时候就已经知道了每个信号处理的方式。信号发送的本质是操作系统对发送信号的硬件信号进行处理,然后操作系统向进程的一个信号位图表的一个位置由0变1,实际是硬件的信号通过操作系统写到进程的进程控制块的信号位图进行写入。然后进程在合适的时候进行信号的操作。
Linux进程的task_struct中也确实采用了位图这种数据来保存信号,用int表示:
uint32_t signals:
00000000 00000000 00000000 00000000
下标位置对应信号的编码。

signal系统调用捕捉信号

在这里插入图片描述
signal系统调用可以对进程的信号进行捕捉,修改方法,但9号和19号信号进行捕捉是无意义的。可以使用signal(2,SIG_DFL)对信号恢复默认的处理方式。
在这里插入图片描述

键盘产生信号

一个计算机,只要一个前台进程,和n多个后台进程,前台进程一旦停止就会变成后台进程,即前台的进程是一直运行的。只要前台进程可以接收到我们键盘发送的信号,一旦键盘识别到键盘的组合键,就会产生信号。1到31号信号是普通信号,34到64是实时信号。没有0信号。进程处理信号的方式有操作系统自己默认的方式,或者自己自定义的方式,和进程可以忽略该信号着三种处理方法。

系统调用产生信号

int kill(pid_t pid, int sig);

进程异常产生信号

如果一个整数除以0,或者对一个空指针解引用,进程都会发送异常信号。进程退出
在这里插入图片描述

软件条件发送信号

Code Dump

Code Dump位文件的转储,对进程异常时保存进程的上下文,Linux虚拟机一般时打开的,Linux的服务器的code dump一般不打开,默认为0。
在这里插入图片描述
在这里插入图片描述
code dump保存了异常退出进程的pid。code dump保存了进程异常退出的信息。

信号保存

因为进程不是立即对信号进行处理的,使用进程要对信号进行保存。

信号抵达

当进程在处理信号对应的处理方式的时候,叫做信号的抵达,进程对信号的操作方式可能有忽略signal(int sign,SIG_IGN),默认的处理方式signal(int sign,SIG_DFL),和自定义捕捉的处理方式。

信号产生到信号抵达之间的状态叫信号未决。

信号未决即信号还在进程task_struct的信号位图中保存着。

进程可以对信号进行阻塞

如果信号未决,进程可以对该信号阻塞,暂时信号不进行抵达,直到进程解除阻塞。

对于普通信号的pending未决位图表,只有能一个信号。在linux中有sigset_t类型的数据来表示这两张信号位图表。也叫信号集。

使用sigprocmask()系统调用接口阻塞block信号集表

1.使用sigemptyset(sigset_t* )对一个位图进行初始化。
2.使用sigaddset(sigset_t*,int sign)对位图的某一个位置为1。
3.使用sigprocmask(int how,sigset_t* set,sigset_t* oldset);通过这个函数才把进程task_struct的阻塞信号位图进行写入,这个时候进程的某个信号才被屏蔽。set为要对那一个信号进行屏蔽,而oldset为输出型参数,其实是set改变后对被block进行恢复。

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;

void handler(int sign)
{
    cout << "收到信号:" << sign <<endl;
    sleep(1);
    exit(0);
}
int main()
{
    cout << "pid: " << getpid() << endl;
    signal(2,handler);
    signal(3,handler);
    sigset_t block,oblock;
    sigemptyset(&block);//对一个变量位图进行初始化
    sigemptyset(&oblock);
    sigaddset(&block,2);//把位图对应的位置置为1
    sigaddset(&block,3);//把位图对应的位置置为1
    sigprocmask(SIG_BLOCK,&block,&oblock);//让进程的block表的对应信号进行屏蔽
    //这里是对2号信号的屏蔽,发送2号信号,信号无法抵达,进程不终止

    while(true)
    {
        sleep(1);
    }
    return 0;
}

9号信号无法被阻塞屏蔽。
sigaddset不是把进程的信号屏蔽,只是把一个局部变量进行修改,sigprocmask才是对阻塞信号集进行写入来屏蔽信号。

sigpending(sigset_t*)检查pending未决信号集

首先我们需要对进程的阻塞的信号集对某几个信号进行屏蔽,我们使用sigpending()获取未决信号集,然后使用sigismember(sig_set* pending,int sign)的每一个未决信号集的位图进行判断。

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;

void Print(sigset_t &pending)
{
    for(int i = 31;i > 0;--i)
    {
        if(sigismember(&pending,i))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
    cout << "pid: " << getpid() << endl;
    sigset_t block,oldblock;
    sigemptyset(&block);
    sigemptyset(&oldblock);
    for(int i = 0;i < 32;i++)
    sigaddset(&block,i);//把位图全置为1
    sigprocmask(SIG_BLOCK,&block,&oldblock);//对所有信号进行屏蔽,9or19无法屏蔽
    
    sigset_t pending;//未决信号表
    while(true)
    {
        sigpending(&pending);//获取未决信号表
        Print(pending);
        sleep(1);
    }
    return 0;
}

该程序除了9号和19号无法屏蔽。

解除信号阻塞

void handler(int sign)
{
    cout << "收到信号:" << sign <<endl;
    sleep(1);
}

void Print(sigset_t &pending)
{
    for(int i = 31;i > 0;--i)
    {
        if(sigismember(&pending,i))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

int main()
{
    cout << "pid: " << getpid() << endl;
    sigset_t block,oldblock;
    sigemptyset(&block);
    sigemptyset(&oldblock);
    for(int i = 0;i < 32;i++)
    {
        sigaddset(&block,i);//把位图全置为1
        signal(i,handler);
    }
    sigprocmask(SIG_BLOCK,&block,&oldblock);//对所有信号进行屏蔽,9or19无法屏蔽
    
    sigset_t pending;//未决信号表
    int count = 0;
    while(true)
    {
        sigpending(&pending);//获取未决信号表
        Print(pending);
        sleep(1);
        count++;
        if(count == 15)
        {
            sigprocmask(SIG_SETMASK,&oldblock,NULL);
//使用旧的block表重新设置,把全部的信号屏幕解除
        }
    }
    return 0;
}

在这里插入图片描述
结果时先发送2号信号再发送3号,信号屏蔽被解除后,是最近的信号先抵达的,这里使用了自定义捕捉,所以3号信号抵达时并未退出,可以知道进程的信号只有最近一次产生的有效。进程信号抵达时,pending表的比特位由1变0是执行信号对应发放前置位0的。

信号的处理时机

进程在内核态到用户态的时候,进行信号的检测和信号的处理。
用户态:是受到操作系统的控制,访问的资源是有限的。访问32位机器的0到3GB的地址空间。
内核态:操作系统的工作状态,能访问大部分资源。让用户用系统调用接口以操作系统的身份访问系统的资源。
用户的进程的代码和数据可以在进程地址空间进行跳转,进行调用和返回。在linux系统当中,CPU有一个CS寄存器,有两个比特位,二进制01和11,分别表示内核态和用户态。
在这里插入图片描述

信号的捕捉sigaction

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);函数来对信号进行屏蔽。
当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字(进行阻塞),当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
void Print(sigset_t &pending)
{
    for(int i = 31;i > 0;--i)
    {
        if(sigismember(&pending,i))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}
void handler(int sign)
{
    cout << "收到信号:" << sign <<endl;
    while(true)
    {
        sigset_t pending;
        sigpending(&pending);
        Print(pending);
        sleep(1);
    }
}

int main()
{
    cout << "pid: " << getpid() << endl;
    struct sigaction act,oldact;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask,3);
    sigaction(2,&act,&oldact);//对2号信号进行屏蔽
    while(true)
    {
        sleep(1);
    }
    return 0;
}

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

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

相关文章

设计模式(九)模版方法模式

请直接看原文:设计模式&#xff08;九&#xff09;模版方法模式_模板方法模式的优缺点-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 1.模版方法模式简介 模版方法模式介…

【架构笔记2】设计不足和过度设计

复杂系统问题设计中有两类现象需要引起关注&#xff1a;设计不足和过度设计&#xff0c;通常第一种比较常见&#xff0c;第二种则也是一种灾难。当然我认为他们都可以被优化&#xff0c;如果用正确的流程引导&#xff0c;在框架模板的限定下放飞&#xff0c;就像教养孩子有个观…

Git实战(1)

一, git log 查看提交日志情况 根据 commitId进行版本回退 git reset --hard commitId(commitId可以是一部分,不用完整的ID) 只输出一行信息: git log --pretty=oneline 快速回退: git reset --hard HEAD^ 回退到上一个版本 git reset --hard HEAD^^ 回退到上上个版本 如果…

力扣74. 搜索二维矩阵(二分查找)

Problem: 74. 搜索二维矩阵 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1&#xff1a;映射为一维数组二分查找 1.由于题目矩阵中的元素整体是升序的&#xff0c;我们可以将其放置在一个大小为 m n m \times n mn的一维数组array中进行二分查找 2.对应的映射关系是ar…

蓝桥杯备赛 day1 | 1. 门牌制作, 2. 迷宫, 3. 乘积尾零

最近正好在刷算法题&#xff0c;报了一个蓝桥杯体验一下&#xff0c;但是钱都交了&#xff0c;高低混个奖好吧&#xff0c;今天做的都是一些填空推理题&#xff0c;相当于用程序写下正解&#xff0c;代码是在Dev C上面写的 #include<iostream> #include<bits/stdc.h&g…

HikariCP与Spring Boot的完美集成,让您的应用更高效、更可靠!

随着Spring Boot的流行&#xff0c;越来越多的开发者选择使用它来构建高效、可扩展的应用程序。然而&#xff0c;在构建应用程序的过程中&#xff0c;数据库连接的管理也是一个非常重要的环节。在这篇文章中&#xff0c;我们将介绍如何将HikariCP这一高效的数据库连接池与Sprin…

性能对比:mysql 5.7-8.0-TiDB 7.5-OceanBase 4.2-MariaDB 10.11-机械硬盘-固态硬盘-

1.mysql 5.7-8.0 5.7比8.0优秀 结果&#xff1a;5.7比8.0优秀 10% 2.机械硬盘和固态硬盘 影响不大&#xff0c;主要是CPU 3. JAVA MYSQL 分开 4.『直属 MySQL 』vs 『Docker MySQL』 vs 『Podman MySQL』 直属最好 &#xff0c;其次是Podman&#xff0c;最后是DOCKER 5.MySQL …

Python光速入门 - Flask轻量级框架

FlASK是一个轻量级的WSGI Web应用程序框架&#xff0c;Flask的核心包括Werkzeug工具箱和Jinja2模板引擎&#xff0c;它没有默认使用的数据库或窗体验证工具&#xff0c;这意味着用户可以根据自己的需求选择不同的数据库和验证工具。Flask的设计理念是保持核心简单&#xff0c…

Qt/事件分发器/事件过滤器

事件分发器 //事件分发器bool event(QEvent* e); //事件分发器&#xff1a;&#xff1a;用途 分发事件 bool MyLabel::event(QEvent* e) {if(e->type() QEvent::MouseButtonPress){//如果是鼠标摁下 拦截事件 不向下分发QMouseEvent* ev static_cast<QMouseEvent*>…

【JS 算法题: 将 json 转换为字符串】

题目简介 其实就是手撕 JSON.stringfy()。 算法实现 输入 原则上来说&#xff0c;输入的是一个 json 对象。但需要考虑到异常情况&#xff0c;即输入了其它类型的数据&#xff0c;比如&#xff1a;12, true, ‘abc’, [‘red’, ‘green’], null, undefined 等。 输出 …

AGM CPLD (AGRV2K )的时钟(外部时钟和片上内部振荡器)

AGM CPLD &#xff08;AGRV2K &#xff09;的时钟(外部时钟和片上内部振荡器) 外部晶振 与 内部振荡器&#xff1a; mcu 和 cpld 联合编程时&#xff0c; 整颗芯片需要一颗外部晶振。 &#xff08;芯片有内部振荡器&#xff0c; 但误差较大&#xff0c; 校准后 5%以内误差&…

LSTM 长短期记忆递归神经网络

1、神经网络简介 1.1 神经网络起源 人工神经网络&#xff08;Aritificial Neural Networks, ANN&#xff09;是一种仿生的网络结构&#xff0c;起源于对人类大脑的研究。人工神经网络&#xff08;Aritificial Neural Networks&#xff09;也常被简称为神经网络&#xff08;Ne…

Vue3_2024_3天【Vue3组合式API~响应式及toRefs】

第一&#xff1a;vue3 中可以两个script标签 第一个&#xff1a;声明组件名 第二个&#xff1a;setup语法糖&#xff08;默认 lang语言是js语言&#xff0c;修改语言须保持一致&#xff09; 若想去掉一个script标签&#xff08;声明组件名称&#xff09;&#xff0c;则可使用插…

八. 实战:CUDA-BEVFusion部署分析-学习CUDA-BEVFusion推理框架设计模式

目录 前言0. 简述1. 回顾一下RAII是什么2. 实现类&#xff0c;接口类与命名空间3. CUDA-BEVFusion设计框架(namespace)4. CUDA-BEVFusion设计框架(接口类)5. CUDA-BEVFusion设计框架(实现类)6. CUDA-BEVFusion设计框架(各个类负责的内容)7. CUDA-BEVFusion中的接口函数和实现类…

failed to connect to ‘127.0.0.1:58526‘: Connection refused

WSA使用体验 链接&#xff1a; 知乎-穿越时间一步到位&#xff0c;教你完美安装Windows 11 Android 安卓子系统 CPU不满足要求 明明是12700H&#xff0c;满足要求&#xff0c;但是应用商店说不满足&#xff0c;在设置&#xff08;注意不是控制面板的区域&#xff09;把地区改…

ChatGPT 4.0使用之论文阅读

文章目录 阅读环境准备打开AskYourPDF进入主站 粗读论文直接通过右侧边框进行提问选中文章内容翻译或概括插图的理解 总结 拥有了GPT4.0之后&#xff0c;最重要的就是学会如何充分发挥它的强大功能&#xff0c;不然一个月20美元的费用花费的可太心疼了&#xff08;家境贫寒&…

HTML~

HTML HTML是一门语言&#xff0c;所有的网页都是用HTML这门语言编写出来的HTML(HyperText Markup Language):超文本标记语言 超文本:超越了文本的限制&#xff0c;比普通文本更强大。除了文字信息&#xff0c;还可以定义图片、音频、视频等内容 标记语言:由标签构成的语言 …

谨用ArrayList中的subList方法

谨用ArrayList中的subList方法 规范一&#xff1a; ArrayList 的 subList 结果不可强转成 ArrayList&#xff0c;否则会抛出 ClassCastException 异常&#xff1a; public static void test7() {List<Integer> list new ArrayList<>();list.add(1);list.add(2);…

云服务器无法Ping通解决

问题: 使用公网IP地址PING云服务器,无法PING通 但是可SSH到服务器,表示通信链路是正常的,可能是端口或路径规则未开放导致 登陆云服务器后台,进行安全组规则查看,发现ICMP没有放行 添加允许ICMP连接规则 成功PING通云服务器

Linux文本处理三剑客:awk(结构化命令)

在Linux操作系统中&#xff0c;grep、sed、awk被称为文本操作“三剑客”&#xff0c;上几期中&#xff0c;我们详细介绍grep、sed、awk的基本使用方法&#xff0c;希望能够帮助到有需要的朋友。 目录 1、前言 2、条件控制语句 语法结构&#xff1a;IF 语法结构&#xff1a…