信号处理: Block Pending Handler 与 SIGKILL/SIGSTOP 实验

1. 信号处理机制的 “三张表”

kill -l :前 31 个信号为系统标准信号。

block pending handler 三张表保存在每个进程的进程控制块 —— pcb 中,它们分别对应了某一信号的阻塞状态、待处理状态以及处理方式。

  • block :通过 sigset_t 类型实现,是一个位字段集合,每一位对应一个信号;如果某一位被设置,则对应的信号会被阻塞;信号的阻塞状态 与 该信号是否被发送到进程 无关

  • pending :与 block 相同,通过 sigset_t 类型实现,用于记录 已经发送给进程但未被处理 的信号。

  • handler :函数指针数组,指向各个信号的处理方法(函数)。

2. 介绍几个信号处理的系统调用
  • sigemptyset :用于初始化一个信号集为空,即将信号集中的所有信号位都清零。

    创建一个 sigset_t 类型的变量,在对该变量进行各种信号处理操作之前,先要使用 sigemptyset 对该变量初始化。

	sigset_t sig;
    sigemptyset(&sig); // 对 sig 初始化, success -> 0, fail -> -1
  • sigaddset :用于在一个已存在的信号集中添加信号。
	sigaddset(&sig, SIGINT); // success return 0, fail return -1
  • sigprocmask :用于更改当前进程的信号掩码,简单来说即设置哪些信号被阻塞。
 sigprocmask(int how, const sigset_t* signal, sigset_t* old_signal);

how 的处理方式, SIG_BLOCK SIG_UNBLOCK SIG_SETMASK

SIG_BLOCK : 设置新的信号掩码,同时保留旧的信号掩码

SIG_UNBLOCK : 取笑新信号掩码中的信号阻塞,并保留旧的信号掩码

SIG_SETMASK : 设置新的信号掩码,并丢弃旧的信号掩码

	sigset_t oldsig;
    sigemptyset(&oldsig);

    sigprocmask(SIG_SETMASK, &sig, &oldsig);
  • sigpending :用于获取当前进程中待处理的信号集。
	sigset_t pending;
    sigemptyset(&pending);
    
    sigpending(&pending);
  • sigismember :用于测试一个信号是否在一个信号集中,存在返回 1,否则返回 0。
	sigismember(&pending, SIGINT);
3. demo —— 示范案例

demo 中主要完成以下四个动作:

  1. 屏蔽 2 号信号 —— SIGINT
  2. 获取当前进程的 pending
  3. 打印 pending 表
  4. 取消对 2 号信号的屏蔽

其中,2.3. 是 “同时” 且 重复 进行的,意味着将出现这样一个现象:当前进程在接收 2 号信号之前,pending 表 2 号信号对应位置为 0;向当前进程发生 2 号信号后,pending 表 2 号信号位置被设置。

以及,取消对 SIGINT 的屏蔽后,2 号信号会被立即递达,进程结束。

1) 屏蔽 2 号信号
#include <iostream>
using namespace std;
#include <signal.h>

int main()
{
    // 1. 屏蔽 2 号信号
    sigset_t block;
    sigset_t old_block;
    sigemptyset(&block);
    sigemptyset(&old_block);

    sigaddset(&block, SIGINT);
    sigprocmask(SIG_SETMASK, &block, &old_block);
    cout << "process pid: " << getpid() << endl;
    cout << "block SIGINT success ..." << endl;
    

    return 0;
}
2) 获取当前进程的 pending 表 | 3) 打印 pending 表
#include <unistd.h>

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

int main()
{
    // ...
    
    while (1)
    {
        // 2. 获取当前 pending 表
        sigset_t pending;
        sigemptyset(&pending);
        sigpending(&pending);

        // 3. 打印 pending 表
        PrintSig(pending);
        
        sleep(1);
    }
    
}

将这部分代码先运行起来,并对该进程发送一个 SIGINT 信号,观察现象:
在这里插入图片描述

当前进程(3988092)pending 表的 2 号信号对应位置被设置,但进程没有退出!

4) 取消对 2 号信号的屏蔽
int main()
{
    while (1) {
        // ...   
        // 4. 取消对 2 号信号对屏蔽
        ++cnt;
        if (cnt == 20)
        {
            sigprocmask(SIG_UNBLOCK, &block, &old_block);
        }
    }
}

为了使 2 号信号恢复且被递达后的观察效果更明显,我们对 PrintSig 函数 做一下优化,再 对 2 号信号的处理程序自定义

介绍一个新的系统调用接口:signal

signal() 允许我们为特定信号指定一个处理函数 —— handler() 是一个参数类型为 int 返回值为 的函数, 当信号到达时,该函数将被调用。

#include <iostream>
using namespace std;
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

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

void handler(int signal)
{
    cout << "2 号信号被递达" << endl;
    exit(1);
}

int main()
{
    signal(SIGINT, handler); // 对 SIGINT 的处理方式重定义

    // 1. 屏蔽 2 号信号
    sigset_t block;
    sigset_t old_block;
    sigemptyset(&block);
    sigemptyset(&old_block);

    sigaddset(&block, SIGINT);
    sigprocmask(SIG_SETMASK, &block, &old_block);
    cout << "process pid: " << getpid() << endl;
    cout << "block SIGINT success ..." << endl;

    int cnt = 0;
    while (1)
    {
        // 2. 获取当前 pending 表
        sigset_t pending;
        sigemptyset(&pending);
        sigpending(&pending);

        // 3. 打印 pending 表 
        PrintSig(pending, cnt);
        sleep(1);

        // 4. 取消对 2 号信号对屏蔽
        ++cnt;
        if (cnt == 20)
        {
            sigprocmask(SIG_UNBLOCK, &block, &old_block);
        }
    }
    return 0;
}

在这里插入图片描述

进程运行 20 秒后,SIGINT 的屏蔽被取消,SIGINT 被递达,进程终止!

4. 对 SIGKILL 和 SIGSTOP 的验证

pid 为 “当前进程” 的 pid

while :; do for i in {1..8}; do kill -$i pid; done; sleep 1; done    # 对进程发送 1~8 号信号
while :; do for i in {10..18}; do kill -$i pid; done; sleep 1; done  # 对进程发送 10~18 号信号
while :; do for i in {20..31}; do kill -$i pid; done; sleep 1; done  # 对进程发送 20~31 号信号

对原代码做出修改:使用 for 循环,让进程阻塞 1~31 号信号

随后,在另一窗口使用 bash 脚本,分别向当前进程发送 1~8 、 10~18 、 20~31 号信号,观察进程的 pending 表;

在过程中,对当前进程发送 9 号信号 和 19 号信号,观察现象。

#include <iostream>
using namespace std;
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

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

void handler(int signal)
{
    cout << "2 号信号被递达" << endl;
    exit(1);
}


int main()
{
    // 1. 屏蔽 1~31 号信号
    sigset_t block;
    sigset_t old_block;
    sigemptyset(&block);
    sigemptyset(&old_block);

    for (int i = 1; i <= 31; i++)
    {
        sigaddset(&block, i);
    }

    sigprocmask(SIG_SETMASK, &block, &old_block);
    cout << "process pid: " << getpid() << endl;
    cout << "block signal success ..." << endl;

    int cnt = 0;
    while (1)
    {
        // 2. 获取当前 pending 表
        sigset_t pending;
        sigemptyset(&pending);
        sigpending(&pending);

        // 3. 打印 pending 表
        PrintSig(pending);
        sleep(2);
    }
    return 0;
}
  • 对当前进程发送 1~8 号信号 和 9 号信号

在这里插入图片描述

对当前进程发送 1~8 号信号,进程没有结束。

对当前进程发送 9 号信号,进程终止!

  • 对当前进程发送 10~18 号信号 和 19 号信号

在这里插入图片描述

对当前进程发送 10~18 号信号,进程没有结束。

对当前进程发送 19 号信号,进程终止!

  • 对当前进程发送 20~31 号信号

在这里插入图片描述

对当前进程发送 20~31 号信号,进程没有结束。

总结:9 号信号 — SIGKILL 及 19 号信号 — SIGSTOP 是特殊信号,不能被阻塞,因为它们具有重要作用!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【补充】倒易点阵基本性质

&#xff08;1&#xff09;任意倒易矢量 r h k l ∗ h a ∗ k b ∗ l c ∗ \mathbf{r}_{hkl}^* h\mathbf{a^*} k\mathbf{b^*} l\mathbf{c^*} rhkl∗​ha∗kb∗lc∗必然垂直于正空间中的(hkl)晶面。 正空间中的(hkl)晶面的法向是[hkl]&#xff0c;和坐标轴的交点为A、B、…

Steam黑神话悟空禁止更新进入游戏的解决方案

首先打开该网站&#xff1a;https://steamdb.info/app/2358720/ 2358720即为游戏ID 网页下翻&#xff0c;找到更新历史&#xff1a;https://steamdb.info/app/2358720/history/ 然后在Steam的steamapps下&#xff0c;找到后缀为2358720的文件&#xff0c;右击记事本打开 将St…

解决银河麒麟V10向日葵远程连接断开问题

解决银河麒麟V10向日葵远程连接断开问题 方法一&#xff1a;重启系统方法二&#xff1a;执行xhost 命令 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 当你在银河麒麟桌面操作系统V10上使用向日葵进行远程连接时&#xff0c;如果遇到频繁断…

Vue项目快速整合WangEditor富文本编辑器

Vue项目快速整合WangEditor富文本编辑器 一、安装依赖 npm i wangeditor --save //富文本编辑器 npm install highlight.js -S //代码高亮 npm install dompurify vue-dompurify-html // 防xss 库二、app.vue代码案例 已对接图片、视频接口 &#xff0c;具体看如下代码…

基于飞腾平台的OpenCV的编译与安装

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

景联文科技精准数据标注:优化智能标注平台,打造智能未来

景联文科技是一家致力于为人工智能提供全面数据标注解决方案的专业公司。 拥有一支由经验丰富的数据标注师和垂直领域专家组成的团队&#xff0c;确保数据标注的质量和专业性。 自建平台功能一站式服务平台&#xff0c;提供从数据上传、标注、审核到导出的一站式服务&#xff0…

Linux安装tomcat及配置环境变量超详细教程

微服务Linux解析部署使用全流程 linux系统的常用命令 Linux安装vim超详细教程 Linux安装JDK及配置环境变量超详细教程 1、上传压缩包 统一创建目录&#xff1a;/usr/local/tomcat&#xff0c;将压缩包上传到这个目录下。拖动文件到这个目录下即可。 2、执行解压命令 先进…

Sentinel-1 数据处理时如何手动下载高程数据

在Sentinel-1 数据数据预处理时&#xff0c;会使用高程数据进行地形校正。但选择自动下载高程时&#xff0c;由于网络原因经常会卡死&#xff0c;造成预处理过程不能正常进行&#xff01; 这个问题经过我的反复实践&#xff0c;可以通过手动下载高程数据来解决。下面是具体方法…

章管家 listUploadIntelligent.htm SQL注入漏洞

漏洞描述&#xff1a; 章管家 listUploadIntelligent.htm 接口处存在SQL注入漏洞&#xff0c;未经身份验证的远程攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息&#xff08;例如&#xff0c;管理员后台密码、站点的用户个人信息&#xff09;之外&#xff0c;甚至在高权限…

软件功能测试需进行哪些测试?第三方软件测评机构有哪些测试方法?

在信息化社会迅速发展的今天&#xff0c;软件功能测试在软件开发生命周期中占据着不可或缺的地位。软件功能测试是评估软件系统是否符合预期功能和用户需求的过程。其重要性体现在提升软件质量、确保用户满意度以及降低维护成本等方面。 软件功能测试是对软件应用程序进行的一…

robomimic应用教程(二)——策略运行与评估

得到训练好的pth后&#xff0c;下一并将其进行部署及效果评估 可以在jupyter notebook中进行此操作&#xff0c;文件为robomimic文件夹中的examples/notebooks/run_policy.ipynb 本文采用pycharm调试 该脚本用于在环境中评估策略&#xff0c;主要包括从model zoo下载checkpoi…

【web开发】Spring Boot 快速搭建Web项目(三)

Date: 2024.08.31 18:01:20 author: lijianzhan 简述&#xff1a;根据上篇原文Spring Boot 快速搭建Web项目&#xff08;二&#xff09;&#xff0c;由于已经搭建好项目初始的框架&#xff0c;以及自动创建了一个启动类文件&#xff08;TestWebApplication.java&#xff09; …

【Python】Daphne:Django 异步服务的桥梁

Daphne 是 Django Channels 项目的一部分&#xff0c;专门用于为 Django 提供支持 HTTP、WebSocket、HTTP2 和 ASGI 协议的异步服务器。Daphne 是一个开源的 Python 异步服务器&#xff0c;它可以帮助开发者运行异步应用程序&#xff0c;并且非常适合与 Django Channels 一起使…

电子电路的基础知识

电子电路是现代电子技术的基础&#xff0c;由电子元件&#xff08;如电阻、电容、电感、二极管、晶体管等&#xff09;和无线电元件通过一定方式连接而成的电路系统。 以下是对电子电路的详细概述&#xff1a; 一、定义与分类 定义&#xff1a;电子电路是指由电子器件和有关无…

解压视频素材下载网站推荐

在制作抖音小说推文或其他短视频时&#xff0c;找到合适的解压视频素材非常重要。以下是几个推荐的网站&#xff0c;可以帮助你轻松下载高质量的解压视频素材&#xff1a; 蛙学网 蛙学网是国内顶尖的短视频素材网站&#xff0c;提供大量4K高清无水印的解压视频素材&#xff0c;…

【记录】Excel|不允许的操作:合并或隐藏单元格出现的问题列表及解决方案

人话说在前&#xff1a;这篇的内容是2022年5月写的&#xff0c;当时碰到了要批量处理数据的情况&#xff0c;但是又不知道数据为啥一直报错报错报错&#xff0c;说不允许我操作&#xff0c;最终发现是因为存在隐藏的列或行&#xff0c;于是就很无语地写了博客&#xff0c;但内容…

如何使用Flux+lora进行AI模型文字生成图片

目录 概要 前期准备 部署安装与运行 1. 部署ComfyUI 本篇的模型部署是在ComfyUI的基础上进行&#xff0c;如果没有部署过ComfyUI&#xff0c;请按照下面流程先进行部署&#xff0c;如已安装请跳过该步&#xff1a; &#xff08;1&#xff09;使用命令克隆 ComfyUI &…

【友元补充】【动态链接补充】

友元 友元的目的是让一个函数或者类&#xff0c;访问另一个类中的私有成员。 友元的关键字friend是一个修饰符。 友元分为友元类和友元函数 1.全局函数作友元 2.类作友元 3.类的一个成员函数作友元 好处&#xff1a;可以通过友元在类外访问类内的私有和受保护类型的成员 坏处…

Python画笔案例-068 绘制漂亮米

1、绘制漂亮米 通过 python 的turtle 库绘制 漂亮米,如下图: 2、实现代码 绘制 漂亮米,以下为实现代码: """漂亮米.py注意亮度为0.5的时候最鲜艳本程序需要coloradd模块支持,安装方法:pip install coloradd程序运行需要很长时间,请耐心等待。可以把窗口最小…

智能Ai语音机器人的应用价值有哪些?

随着时间的推移&#xff0c;人工智能的发展越来越成熟&#xff0c;智能时代也离人们越来越近&#xff0c;近几年人工智能越来越火爆&#xff0c;人工智能的应用已经开始渗透到各行各业&#xff0c;与生活交融&#xff0c;成为人们无法拒绝&#xff0c;无法失去的一个重要存在。…