Linux信号处理机制基础

news2024/11/15 12:21:13

什么是信号

  • 信号在最早的UNIX系统中即被引入,已有30多年的历史,但只有很小的变化。
  • 信号是提供异步事件处理机制的软件中断
  • 进程之间可以相互发送信号,这使信号成为一种进程间通信(Inter-ProcessCommunication,lPC)的基本手段

信号的名称与编号

  • 信号是很短的消息,本质就是一个整数,用以区分代表不同事件的不同信号。为了便于记忆,在signum.h头文件中用一组名字前缀为SIG的宏来标识信号,即为信号的名字。
  • 通过kill -l命令可以查看信号
  • 一共有62个信号,其中前31个信号为不可靠的非实时信号后31个为可靠的实时信号

 常用信号

信号处理 

  • 忽略:什么也不做,SIGKILL(9)和SIGSTOP(19)不能被忽略
  • 默认:在没有人为设置的情况,系统缺省的处理行为。
  • 捕获:接收到信号的进程会暂停执行,转而执行一段事先编写好的处理代码,执行完毕后再从暂停执行的地方继续运行,

信号处理函数 

signal函数

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

功能:设置调用进程针对特定信号的处理方式

参数:signum         信号编号
        handler 信号的处理方式,可以如下取值
                SIG_IGN        -忽略
                SIG_DFL       - 默认
                信号处理函数指针        -捕获 
返回值:成功返回原信号处理方式,如果之前未处理过则返回NULL,失败返回SIG_ERR

 代码演示

//信号处理
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
//信号处理函数
void sigfun(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
    }
int main(){
    // 对2号信号进行忽略处理
    //接下来程序就有了忽略2号信号的能力
    if(signal(SIGINT,SIG_IGN) == SIG_ERR){
        perror("signal");
        return -1;
    }
    //对2号信号进行捕捉处理
    if(signal(SIGINT,sigfun) == SIG_ERR){
        perror("signal");
        return -1;
    }
    // if(signal(SIGINT,SIG_DFL) == SIG_ERR){
    //     perror("signal");
    //     return -1;
    // }
    for(;;);
    return 0;
}

 信号处理流程

        当有信号到来时,内核会保存当前进程的栈帧,然后再执行信号处理函数。当信号处理函数结束后,内核会恢复之前保存的进程的栈帧,使之继续执行

太平间信号

        无论一个进程是正常终止还是异常终止,都会通过系统内核向其父进程发送SIGCHLD(17)信号。父进程完全可以在针对SIGCHLD(17)信号的信号处理函数中,异步地回收子进程的僵尸,简洁而又高效

        在信号处理函数执行期间,如果有多个相同的信号到来,则只保留一个,其余统统丢弃。如果我们在一次信号处理函数执行期间只进行一次收尸,就会导致漏网的僵尸。那我们又该如何对这些僵尸进程进行回收,我们可以在一次信号处理函数期间尽可能多的回收僵尸进程。此外为防止长时间等待回收子进程影响父进程的执行,我们可以采用非阻塞方式回收僵尸进程。

代码演示 

//太平间信号
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<errno.h>

//信号捕获处理函数
void sigchild(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
    sleep(2);//假装信号处理函数很耗时
    for(;;){
        pid_t pid = waitpid(-1,NULL,WNOHANG);
        if(pid == -1){
            if(errno == ECHILD){
                printf("%d进程:没有子进程了\n",getpid());
                break;
            }else{
                perror("waitpid");
                return ;
            }
        }else if(pid == 0){
            printf("子进程正在运行,回收不了\n");   
            break;
        }else{
            printf("%d进程:回收了%d进程的僵尸\n",getpid(),pid);
        }
    }
}
    /*for(;;){
        pid_t pid = wait(NULL);
        if(pid == -1){
            if(errno == ECHILD){
                printf("%d进程:没有子进程了\n",getpid());
                break;
            }else{
                perror("wait");
                return ;
            }
        }
        printf("%d进程:回收了%d进程的僵尸\n",getpid(),pid);
    }
}*/
int main(){
    if(signal(SIGCHLD,sigchild) == SIG_ERR){
        perror("signal");
        return -1;
    }
    //创建多个子进程
    for(int i = 0; i < 5;i++){
        pid_t pid = fork();
        if(pid == -1){
            perror("fork");
            return -1;
        }
        if(pid == 0){
            printf("%d进程:我是子进程\n",getpid());
            //sleep(1 + i);
            sleep(1);
            return 0;
        }
    }
    //创建老六
    pid_t oldsix = fork();
    if(oldsix == -1){
        perror("fork");
        return -1;
    }
    if(oldsix == 0){
        printf("%d进程:我是老六\n",getpid());
        sleep(15);
        return 0;
    }
    //父进程代码
    for(;;);
    return 0;
}

信号的继承与恢复

  • fork函数创建的子进程会继承父进程的信号处理方式
    • 父进程中对某个信号进行捕获,则子进程中对该信号依然捕获
    • 父进程中对某个信号进行忽略,则子进程中对该信号依然忽略

代码演示 

//验证子进程是否继承父进程的信号处理方式
#include <stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>

void sigfun(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
}
int main(){
    //忽略2号信号
    if(signal(SIGINT,SIG_IGN) == SIG_ERR){
        perror("signal");
        return -1;
    }
    //捕获3号信号
    if(signal(SIGQUIT,sigfun) == SIG_ERR){
        perror("signal");
        return -1;
    }
    //创建子进程
    pid_t pid = fork();
    if(pid == -1){
        perror("fork");
        return -1;
    }
    //子进程暂时不结束
    if(pid == 0){
        printf("%d进程:我是子进程\n",getpid());
        while(1){
            
        }
        return 0;
    }
        
    //父进程
    printf("%d进程:我是父进程\n",getpid());
    sleep(1);
    return 0;
}

 由于父子进程共用终端设备我们需要在vi上进行,开启两个窗口,向子进程发送2号和3号信号。

窗口1 
day06$./fork
18338进程:我是父进程
18339进程:我是子进程
day06$kill -2 18317
day06$
day06$kill -3 18317
day06$kill -3 18317
day06$kill -3 18317

窗口2
day06$./fork
18316进程:我是父进程
18317进程:我是子进程
day06$18317进程:捕获到3号信号
18317进程:捕获到3号信号
18317进程:捕获到3号信号
  • exec家族函数创建的新进程对信号的处理方式和原进程稍有不同
    • 原进程中被忽略的信号,在新进程中依然被忽略
    • 原进程中被捕获的信号,在新进程中被默认处理

 代码演示

execl.c

//新进程是否继承旧进程的信号处理方式
#include <stdio.h>
#include<unistd.h>
#include<signal.h>
//信号处理函数
void sigfun(int signum){
    printf("%d进程:捕获到%d号信号\n",getpid(),signum);
    return 0;
}
int main(){
    //忽略SIGINT信号
    if(signal(SIGINT,SIG_IGN) == SIG_ERR){
        perror("signal");
        return -1;
    }
    //捕获SIGQUIT信号
    if(signal(SIGQUIT,sigfun) == SIG_ERR){
        perror("signal");
        return -1;
    }
    //变身
    if(execl("./new","new",NULL) == -1){
        perror("execl");
        return -1;
    }

    return 0;
}

new.c

//变身目标
#include<stdio.h>
int main(){
    while(1){}
    return 0;
}
day06$./execl
^C^C^C^C^C^C^C^C^C^\退出 (核心已转储)
day06$

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

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

相关文章

水控器数码管驱动方案

目录 方案1 方案2 总结 方案1 数码管驱动电路选用2片74HC595和外围电阻实现&#xff0c;如图1所示。74HC595的封装为S0-16(窄体)&#xff0c;芯片价格0.42&#xff0c;整个LED驱动电路成本约0.9元(不包含数码管)。 图1、74HC595驱动电路 方案2 为减少PCB板密度&#xff0c;数…

x86中部署docker环境

使用dockerhub搜索Ubuntu x86 1、拉取镜像 docker pull balenalib/odyssey-x86-ubuntu 2、查看镜像 docker images 3、保存镜像 docker save -o ubuntuX86.tar ubuntu/x86:v1 4、加载镜像 docker load -i ubuntuX86.tar 5、创建并运行容器 docker run -itd balenalib/odyssey-…

灵办AI搜索引擎和文档总结工具

前言—— 在信息爆炸的时代&#xff0c;如何高效地获取和处理知识成为了每个人面临的挑战。随着人工智能技术的迅猛发展&#xff0c;本文将深入探讨这一创新工具的功能与优势&#xff0c;以及如何在日常生活和工作中充分利用它&#xff0c;开启智能化的信息获取新篇章。 点击…

计算机毕业设计选题推荐-剧本杀服务平台-剧本杀拼团管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

【刷课利器】一条指令完成网页视频完播

网页右击“检查” 点击控制台控制台输入 document.querySelector(‘video’).currentTime document.querySelector(‘video’).duration

封装CUDA为动态链接库+Qt调用

由于工作需要在Qt中调用CUDA做并行计算&#xff0c;加速算法实现时间&#xff0c;发现有两种方法可以在Qt中调用CUDA代码。 第一种是在项目中创建CUDA的cu文件&#xff0c;编写CUDA的核函数给其他的QT代码调用&#xff0c;Qt的代码正常编译&#xff0c;CUDA代码使用nvcc编译器编…

无敌保姆级华为认证 HCIE 笔试+实验考试指引,简直不要太详细

HCIE&#xff08;Huawei Certified ICT Expert&#xff0c;华为认证ICT专家&#xff09;是华为认证体系中最高级别的ICT技术认证&#xff0c;旨在打造高含金量的专家级认证&#xff0c;为技术融合背景下的ICT产业提供新的能力标准&#xff0c;以实现华为认证引领ICT行业技术认证…

网安面试设备篇幅:安全准入

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330#rd 《网安面试指南》http://mp.weixin.qq.com/s…

悦数 RAG 正式亮相 :从知识到应用的飞跃,只要几分钟

自 2023 年 8 月悦数与 LlamaIndex 联合发布 Graph RAG 以来&#xff0c;该技术就一直处于技术潮流的前沿。它通过提供更具上下文感知的能力和数据训练的方法&#xff0c;缓解了传统搜索增强技术的幻觉&#xff0c;确保所提供的回复不仅精确&#xff0c;而且有足够丰富的信息。…

科目三灯光模拟满分操作大全!建议收藏

今天一起备考一下科三的灯光模拟考试吧~它可以说是科目三中容易被扣分的操作了&#xff0c;考试开始一旦操作错误&#xff0c;就直接挂科了&#xff01;要想满分通过&#xff0c;这里为大家总结了下面这些窍门~ 操作步骤归类总结 01.开启近光灯 语音指令&#xff1a; 夜间与…

sql 4,创建表类型

1&#xff0c;整数类型(类型,占有空间,范围)标准sql:int / integer 4字节 无符号 0 - 2/32-1 有符号 -2 31 / 2 / 31 -1 smallint 2字节 无符号 0 - 2/16-1 有符号 -2 17 / 2 / 17 -1mysql方言:tinyint 1字节 无符号 0 - 2/8 -1 有符号 -2 7 / 2/7-1med…

Dnspy代码分析/反编译工具的简单使用:以骑砍2为例

前言&#xff1a; 如果我们需要做些反编译工作&#xff0c;改变游戏源码的时候&#xff0c;且该项目是由C#制作而成&#xff0c;便可以使用Dnspy工具。 1&#xff0c;安装 代码分析工具dnspy&#xff1a; ​ ​ 2&#xff0c;使用&#xff1a; 我们拿《骑砍2》举例&#x…

【IDEA】一键重启多个服务

点击Edit Configurations 点击加号&#xff0c;选择Compound 添加需要重启的服务&#xff0c;保存 选择配置好的Compound,一键重启 附加&#xff1a; 调整服务运行内存&#xff0c;Add VM options&#xff0c;填写合适的内存大小

日观芯设、亿方联创即将亮相IDAS 2024设计自动化产业峰会!

第二届设计自动化产业峰会IDAS 2024&#xff08;Intelligent Design Automation Summit 2024&#xff09;将于2024年9月23日-24日在上海张江科学会堂隆重举行。 上海日观芯设自动化有限公司、亿方联创科技有限公司将亮相峰会&#xff01;期待与您相聚&#xff0c;与全球行业领…

登上神坛!这本代码逐行解读注释的transformer宝藏书籍,哪怕是零编程基础也能学懂!

PART.01 transformer必看好书 不管你是现在要学transformer&#xff0c;还是以后要学&#xff0c;这本书都值得你花时间来认真学习&#xff01; 别看它封面平平无奇&#xff0c;这可还是除了《处理几乎所有机器学习问题》之外&#xff0c;我看到的第二本代码解读注释如此详细…

汽车小程序怎么做 汽车服务小程序系统开发制作方法

最近很多老板想要做一个自己公司的汽车服务小程序系统&#xff0c;但是不知道该怎么做&#xff0c;本次瀚林就为大家详细介绍一下汽车服务小程序系统的开发制作方法为大家做参考。 目前市面上的汽车服务有很多类型例如常见的&#xff1a;汽车维修、汽车用品、养护、汽车销售、新…

【动态规划 逆向】837. 新 21 点

本文涉及知识点 C动态规划 LeetCode837. 新 21 点 爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏&#xff0c;描述如下&#xff1a; 爱丽丝以 0 分开始&#xff0c;并在她的得分少于 k 分时抽取数字。 抽取时&#xff0c;她从 [1, maxPts] 的范围中随机获得一个整数作…

常用的人力资源管理系统的价格是多少?

企业的发展实质上就是企业人才的发展&#xff0c;做好人才管理是企业稳步发展的重要手段。许多企业意识到这点也开始建立自己的人力资源管理体系&#xff0c;但往往被自己遇到的复杂事务性问题所束缚&#xff0c;无法深入的去做人力资源管理。随着互联网的发展&#xff0c;人力…

3个方法对症下药:iphone备忘录删了怎么恢复?

iPhone的备忘录应用为我们的生活提供了很多便利&#xff0c;我们可以使用备忘录来记录生活中重要的事项&#xff0c;如密码&#xff0c;行程、会议内容等。但是&#xff0c;如果这些备忘录的内容不小心删除了怎么办呢&#xff1f;今天这篇文章就是来解决大家关于iPhone备忘录删…

MATLAB智能优化算法-学习笔记(1)——遗传算法求解0-1背包问题【过程+代码】

一、问题描述 (1)数学模型 (2)模型总结 目标函数:最大化背包中的总价值 Z。约束条件:确保背包中的物品总重量不超过容量 W。决策变量:每个物品是否放入背包,用0或1表示。这个数学模型是一个典型的0-1整数线性规划问题。由于其NP完全性,当问题规模较大时,求解此问题通…