Linux信号——信号的处理(3)

news2025/4/7 16:26:54

信号是什么时候被处理?

进程从内核态,切换到用户态的时候,信号会被检测处理。
内核态:操作系统的状态,权限级别高
用户态:你自己的状态

内核态和用户态

进程地址空间第三次
所谓的系统调用本质其实是一堆函数指针数组。
1.我们使用系统调用或者访问系统数据,其实还是在我们进程的地址空间内进行跳转的。

2.进程无论如何切换,总能找到OS
我们访问OS,本质是通过我的进程的地址空间的[3,4]GB来访问的。
在这里插入图片描述

3.操作系统是如何运行的
信号技术本来就是通过软件的方式,来模拟的硬件中断
OS的周期时钟中断:非常高的频率,非常短的时间,给CPU发送中断——CPU不断进程处理中断。
操作系统是一个死循环,不断在接受外部的其他硬件中断。

4.操作系统不相信任何用户
必须要能区分当前用户的运行模式,所以就有了用户态和内核态。

信号是如何被处理?

在这里插入图片描述

捕捉信号还有其他方式吗?

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数说明
signum: 要操作的信号编号(如 SIGINT、SIGTERM 等)
act: 指向新信号动作结构的指针,如果为 NULL 则不改变当前处理方式
oldact: 输出型参数,用于保存原信号动作结构的指针,如果为 NULL 则不保存
返回值
成功时返回 0,失败时返回 -1 并设置 errno。

struct sigaction {
    void     (*sa_handler)(int);         // 信号处理函数
    void     (*sa_sigaction)(int, siginfo_t *, void *); // 替代的信号处理函数
    sigset_t sa_mask;                    // 执行处理函数时要阻塞的信号
    int      sa_flags;                   // 修改行为的标志
    void     (*sa_restorer)(void);       // 已废弃
};

关于sa_mask变量

  1. 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字(屏蔽该信号)
  2. 如果我们处理完对应的信号,该信号默认也会从信号屏蔽字中进行移除。(解除屏蔽该信号)
    为什么会这样?原因:不想让信号,嵌套式地对同一个信号进行捕捉处理。

用例子解释:

#include<iostream>
#include<signal.h>
void Print(sigset_t pending)
{
    std::cout<<" curr process pending: ";
    for(int sig = 31;sig > 0;sig--)
    {
        if(sigismember(&pending,sig)) std::cout << "1";
        else std::cout <<"0";
    }
    std::cout << std::endl;
}
void handler(int signo)
{
    std::cout << "signal: " << signo <<std::endl;
    //不断获取当前进程的pending信号集并打印
    sigset_t pending;
    sigemptyset(&pending);
    while(true)
    {
        sigpending(&pending);
        Print(pending);
        sleep(1);
    }
}

int main()
{
    struct sigaction act,oact;
    act.sa_handler = handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);

    sigaction(2,&act,&oact);
    while(true)sleep;
}

在这里插入图片描述

在调用信号处理函数时,除了当前信号被自动屏蔽外,还希望自动屏蔽另外一些信号,则要用sa_mask字段说明。
例子:

int main()
{
    struct sigaction act,oact;
    act.sa_handler = handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask,3);
    sigaddset(&act.sa_mask,4);
    sigaddset(&act.sa_mask,5);
    //除了屏蔽当前正在处理的函数,还屏蔽3,4,5号信号
    sigaction(2,&act,&oact);
    while(true)sleep;
}

子进程信号版的进程退出

子进程退出,父进程不wait,子进程就会僵尸。
子进程退出,不是默默退出的,会在退出的时候,向父进程发送信号(17.SIGHLD
如何证明?

#include<iostream>
#include<signal.h>
#include<unistd.h>
void handler(int signo)
{
    std::cout <<"child quit, father get a signo: "<< signo << std::endl;
}
int main()
{
    signal(SIGCHLD,handler);

    pid_t id = fork();
    if(id == 0)
    {
        //child
        int cnt = 5;
        while(cnt--)
        {
            std::cout<<"I am child process: "<<getpid()<<std::endl;
            sleep(1);
        }
        std::cout<<"child process died"<<std::endl;
        exit(0);
    }
    //father
    while(true) sleep(1);

    return 0;
}

结果:确实子进程退出时向父进程发送了17号信号
在这里插入图片描述
所以当子进程退出时,发送17号信号,刚好我们将信号进行捕获,自定义处理信号,将该子进程进行回收,就有如下代码。

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void handler(int signo)
{
    std::cout <<"child quit, father get a signo: "<< signo << std::endl;
}

void CleanupChild(int signo)
{
    //v1
    // if(signo == SIGCHLD)
    // {
    //     pid_t rid = waitpid(-1,nullptr, 0);//-1表示任意一个子进程
    //     if(rid >0)
    //     {
    //         std::cout << "wait child success: " << rid << std::endl;
    //     }
    // }

    //v2-同时退出一百个进程
    // if(signo == SIGCHLD)
    // {
    // //但是如果同时要回收100个子进程,这时pending位图中在短时间内只能保存一次信号,所以加上循环,不停的回收
	//     while(true)
	//     {
	//         pid_t rid = waitpid(-1,nullptr, 0);//-1:表示任意一个子进程
	//         if(rid >0)
	//         {
	//             std::cout << "wait child success: " << rid << std::endl;
	//         }
	//         else if(rid <= 0) break;
	//     }
    // }
    //v3-50个进程退出,50个进程没有退出
    if(signo == SIGCHLD)
    {
    //但是如果同时要回收100个子进程,这时pending位图中在短时间内只能保存一次信号,所以加上循环,不停的回收
	    while(true)
	    {
	        pid_t rid = waitpid(-1,nullptr, WNOHANG);//-1:表示任意一个子进程//以非阻塞方式等待
	        if(rid >0)
	        {
	            std::cout << "wait child success: " << rid << std::endl;
	        }
	        else if(rid <= 0) break;
	    }
    }
    std::cout <<"wait sub process done"<<std::endl;
}
int main()
{
    signal(SIGCHLD,CleanupChild);

    pid_t id = fork();
    if(id == 0)
    {
        //child
        int cnt = 5;
        while(cnt--)
        {
            std::cout<<"I am child process: "<<getpid()<<std::endl;
            sleep(1);
        }
        std::cout<<"child process died"<<std::endl;
        exit(0);
    }
    //father
    while(true) sleep(1);

    return 0;
}

版本v1
特点

  1. 使用阻塞方式等待(options=0)
  2. 每次只能回收一个子进程

问题

  1. 如果有多个子进程同时退出,可能会丢失信号
  2. 阻塞调用可能会影响主程序执行

版本v2
改进

  1. 通过循环可以回收多个子进程,解决了多个子进程同时退出的问题。

问题

  1. 仍然是阻塞调用,如果子进程没有退出会一直阻塞。

版本v3
优点

  1. 使用 WNOHANG 非阻塞选项,不会阻塞主程序执行。
  2. 可以一次性回收所有已退出的子进程。

更简单的回收子进程的方式

直接忽略它,将SIGCHLD设置成SIG_IGN,即 signal(SIGCHLD,SIG_IGN);
这样子进程在终止时会被自动清理掉,不会产生僵尸进程,也不会通知父进程。
缺点:仅仅只是退出进程,无法通过自定义函数的方式获取子进程的id,退出码等相关信息。

:SIGCHLD的默认处理动作是IGN(忽略),为什么还要手动设置成SIG_IGN?
这是系统的一个特性,仅在Linux环境下。
设置系统层的IGN,进程终止时,会产生僵尸进程。
设置用户层的SIG_IGN,系统会将进程终止,不产生僵尸进程。

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

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

相关文章

Pod的调度

在默认情况下&#xff0c;一个Pod在哪个Node节点上运行&#xff0c;是由Scheduler组件采用相应的算法计算出来的&#xff0c;这个过程是不受人工控制的。但是在实际使用中&#xff0c;这并不满足的需求&#xff0c;因为很多情况下&#xff0c;我们想控制某些Pod到达某些节点上&…

LabVIEW面向对象编程设计方法

一、概述 面向对象编程&#xff08;OOP&#xff09;在软件开发中占据重要地位&#xff0c;尤其是在大规模软件项目中。它与小型程序开发思路不同&#xff0c;更注重未来功能的升级与扩展。在设计阶段&#xff0c;需思考如何构建既灵活又稳定的系统&#xff0c;这涉及众多设计方…

Dify票据识别遇到的分支判断不准确问题

已测试这篇文章中 https://zhuanlan.zhihu.com/p/5465385787 使用多分支条件判断使用不同的大模型识别图片内容 发现了细节问题。在使用时若不注意&#xff0c;分支会出现走向不准的问题。 需要关注部分 下方红框处。1&#xff0c;2后不能跟点。否则会出问。除此之外&#xff0…

《全栈+双客户端Turnkey方案》架构设计图

今天分享一些全栈双客户端Turnkey方案的架构与结构图。 1&#xff1a;三种分布式部署方案:网关方案&#xff0c;超级服务器单服方案&#xff0c;直连逻辑服方案 2: 单服多线程核心架构: 系统服务逻辑服服务 3: 系统服务的多线程池调度设计 4:LogicServer Update与ECS架构&…

某碰瓷国赛美赛,号称第三赛事的数模竞赛

首先我非常不能理解的就是怎么好意思自称第三赛事的呢&#xff1f;下面我们进行一个简单讨论&#xff0c;当然这里不对国赛和美赛进行讨论。首先我们来明确一点&#xff0c;比赛的含金量由什么来定&#xff1f;这个可能大家的评价指标可能不唯一&#xff0c;我通过DeepSeek选取…

【大模型深度学习】如何估算大模型需要的显存

一、模型参数量 参数量的单位 参数量指的是模型中所有权重和偏置的数量总和。在大模型中&#xff0c;参数量的单位通常以“百万”&#xff08;M&#xff09;或“亿”&#xff08;B&#xff0c;也常说十亿&#xff09;来表示。 百万&#xff08;M&#xff09;&#xff1a;表示…

Mysql 数据库编程技术01

一、数据库基础 1.1 认识数据库 为什么学习数据库 瞬时数据&#xff1a;比如内存中的数据&#xff0c;是不能永久保存的。持久化数据&#xff1a;比如持久化至数据库中或者文档中&#xff0c;能够长久保存。 数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长…

Mysql慢查询设置 和 建立索引

1 .mysql慢查询的设置 slow_query_log ON //或 slow_query_log_file /usr/local/mysql/data/slow.log long_query_time 2 修改后重启动mysql 1.1 查看设置后的参数 mysql> show variables like slow_query%; --------------------------------------------------…

【Android】界面布局-相对布局RelativeLayout-例子

题目 完成下面相对布局&#xff0c;要求&#xff1a; 中间的button在整个屏幕的中央&#xff0c;其他的以它为基准排列。Hints&#xff1a;利用layout_toEndof,_toRightof,_toLeftof,_toStartof完成。 结果演示 代码实现 <?xml version"1.0" encoding"u…

Spring Boot 中使用 Redis:从入门到实战

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

7-1 素数求和(线性筛实现)

7-1 素数求和。 分数 10 中等 全屏浏览 切换布局 作者 魏英 单位 浙江科技大学 输入两个正整数m和n&#xff08;1<m<n<500&#xff09;统计并输出m和n之间的素数个数以及这些素数的和。 输入格式: 输入两个正整数m和n&#xff08;1<m<n<500&#xff0…

ZKmall开源商城多云高可用架构方案:AWS/Azure/阿里云全栈实践

随着企业数字化转型的加速&#xff0c;云计算服务已成为IT战略中的核心部分。ZKmall开源商城作为一款高性能的开源商城系统&#xff0c;其在多云环境下的高可用架构方案备受关注。下面将结合AWS、Azure和阿里云三大主流云平台&#xff0c;探讨ZKmall的多云高可用架构全栈实践。…

leetcode二叉树刷题调试不方便的解决办法

1. 二叉树不易构建 在leetcode中刷题时&#xff0c;如果没有会员就需要将代码拷贝到本地的编译器进行调试。但是leetcode中有一类题可谓是毒瘤&#xff0c;那就是二叉树的题。 要调试二叉树有关的题需要根据测试用例给出的前序遍历&#xff0c;自己构建一个二叉树&#xff0c;…

颜色性格测试:探索你的内在性格色彩

颜色性格测试&#xff1a;探索你的内在性格色彩 在我们的日常生活中&#xff0c;颜色无处不在&#xff0c;而我们对颜色的偏好往往能反映出我们内在的性格特质。今天我要分享一个有趣的在线工具 —— 颜色性格测试&#xff0c;它能通过你最喜欢的颜色来分析你的性格倾向。 &…

CMake学习--Window下VSCode 中 CMake C++ 代码调试操作方法

目录 一、背景知识二、使用方法&#xff08;一&#xff09;安装扩展&#xff08;二&#xff09;创建 CMake 项目&#xff08;三&#xff09;编写代码&#xff08;四&#xff09;配置 CMakeLists.txt&#xff08;五&#xff09;生成构建文件&#xff08;六&#xff09;开始调试 …

神经网络入门:生动解读机器学习的“神经元”

神经网络作为机器学习中的核心算法之一&#xff0c;其灵感来源于生物神经系统。在本文中&#xff0c;我们将带领大家手把手学习神经网络的基本原理、结构和训练过程&#xff0c;并通过详细的 Python 代码实例让理论与实践紧密结合。无论你是编程新手还是机器学习爱好者&#xf…

web漏洞靶场学习分享

靶场&#xff1a;pikachu靶场 pikachu漏洞靶场漏洞类型: Burt Force(暴力破解漏洞)XSS(跨站脚本漏洞)CSRF(跨站请求伪造)SQL-Inject(SQL注入漏洞)RCE(远程命令/代码执行)Files Inclusion(文件包含漏洞)Unsafe file downloads(不安全的文件下载)Unsafe file uploads(不安全的文…

MCP over MQTT:EMQX 开启物联网 Agentic 时代

前言 随着 DeepSeek 等大语言模型&#xff08;LLM&#xff09;的广泛应用&#xff0c;如何找到合适的场景&#xff0c;并基于这些大模型构建服务于各行各业的智能体成为关键课题。在社区中&#xff0c;支持智能体开发的基础设施和工具层出不穷&#xff0c;其中&#xff0c;Ant…

ACM代码模式笔记

系列博客目录 文章目录 系列博客目录1.换行符 1.换行符 nextInt()、nextDouble() 等不会消耗换行符&#xff1a; 当使用 nextInt() 或 nextDouble() 读取数字时&#xff0c;它只读取数字部分&#xff0c;不会消耗掉输入后的换行符。 nextLine() 会读取并消耗换行符&#xff1a…

[王阳明代数讲义]具身智能才气等级分评价排位系统领域投射模型讲义

具身智能才气等级分评价排位系统领域投射模型讲义 具身智能胆识曲线调查琴语言的行为主义特性与模式匹配琴语言的"气质邻域 "与气度&#xff0c;云藏山鹰符号约定 琴语言的"气质邻域 "与气度&#xff0c;一尚韬竹符号约定 琴语言的"气质邻域 "与…