Linux进程信号处理:深入理解与应用(1)

news2025/2/4 8:51:22

 

                                               🎬慕斯主页修仙—别有洞天

                                              ♈️今日夜电波:it's 6pm but I miss u already.—bbbluelee

                                                                0:01━━━━━━️💟──────── 3:18
                                                                    🔄   ◀️   ⏸   ▶️    ☰  

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


 

目录

Linux进程信号的概念

引入进程信号

信号的产生

回顾进程的运行

认识进程信号

通过signal替换信号

通过raise给自己发信号

通过abort终止自己

具体信号的产生(下一篇内容)


Linux进程信号的概念

        什么叫做信号?Linux进程信号是一个通知机制,用于在进程之间传递信息和控制进程行为。

        Linux进程信号是操作系统中的一种通信机制,它允许内核或其他进程向目标进程发送消息,这些消息被称为信号。信号可以由多种事件触发,包括硬件异常、软件事件、用户交互等。例如,当用户按下Ctrl+C时,会产生一个中断信号(SIGINT),通知前台进程终止。

        此外,Linux系统中的信号可以分为两类:非可靠信号和可靠信号。非可靠信号是Unix早期版本的信号,编号为1到31。它们不可靠,因为不能被捕获或忽略。可靠信号编号为34到64,它们可以被捕获、阻塞或忽略,提供了更多的控制能力

        综上所述,Linux进程信号是一种灵活的通信机制,它不仅能够响应系统事件,还能够实现进程间的通信和控制。了解信号的概念对于进行Linux编程和管理是非常重要的。

引入进程信号

        通过一个例子了解信号:日常生活中,我们经常会碰到红绿灯,当我们看到红绿灯时就算是碰到了一种信号,我们在看到它后会识别它,“即便没看到红绿灯我们也知道对应的灯亮,意味着什么”,当你等红绿灯的时候可能在玩手机或者干什么,但是“红绿灯信号的变化跟你看手机这件事是不冲突的”,此时,在看手机的你注意到变成了红绿灯变成了绿灯,但是,“你没有立刻过红绿灯而是用手机回完信息后才走”。

         上面提到的种种行为实际上也对应着进程信号的种种特点:(1)信号没有产生的时候,其实我们就已经知道怎么处理这信号了。(2)信号的到来,我们并不清楚具体是什么时候,信号的到来期间,我正在做工作,所以信号的产生是异步的。(3)信号产生了,我们不一定立刻去处理它,而是我们在合适的时候处理。

信号的产生

回顾进程的运行

        进程在运行时,前台进程(命令行操作的时候)只能有一个,后台进程可以有多个。一般情况下,可以通过 Ctrl+c 终止前台进程,Ctrl+z 暂停进程。我们通过进程有没有能力接受用户输入来判断是否为前台进程。

        需要注意的是:前台进程不能被暂停(也就是Ctrl+z),被Ctrl+z后会被放到后台再暂停。如果被shell也是进程,OS会自动把shell提到前台或者后台。

        通过以下命令来设置对应的前、后台进程:

./exe程序 //运行前台进程
./exe程序 & //运行后台进程

        通过以下命令来查看后台进程:

jobs //查看所有后台进程的属性

        通过以下命令来改变后台进程:

bg number //让进程在后台跑起来
Ctrl+z 接着 bg number //将进程放到后台运行
fg number //把进程放到前台运行

        通过以下命令查看运行的进程:

ps axj //后面通常还会跟管道过滤

认识进程信号

        通过kill -l 命令查看所有进程信号:

        通常我们将1-31号的信号称为普通信号,34-64称为实时信号,没有0号、32号、33号信号!

        需要注意的是:每一个进程都有一张自己的函数指针数组,数组的下标和信号编号强相关。实际上,进程可以通过类似位图的数据结构表示自己是否收到了信号:比特位的位置,决定信号编号;内容,决定是否收到信号。可以简要理解:(后续介绍signal()函数会理解位图以及函数指针数组)

struct task_struct
{
    //信号位图0000 0010
    uint32_t sigmap;
    //...
}

        无论信号有多少种产生方式,永远只能让OS向目标进程发送!为什么呢?因为OS是所有进程的管理者!

通过signal替换信号

        signal()函数的原型如下:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
  • 参数
    • signum:这是信号的编号,代表你想要处理的信号类型。可以通过终端输入kill -l来查看系统支持的信号列表。需要注意的是,并非所有信号都可以被捕获,例如SIGKILL和SIGSTOP信号是不能被捕获的。
    • handler:这是一个函数指针,指向当信号发生时应该调用的函数。如果不希望改变信号的默认行为,可以将此参数设置为特定的常数。
  • 处理方式
    • SIG_IGN:表示忽略该信号,即信号发生时不采取任何行动。
    • SIG_DFL:表示采用系统默认的处理方式,通常是终止进程或忽略该信号。
    • 自定义处理函数:如果你希望在信号发生时执行特定的操作,可以设置一个自定义的处理函数。这个函数通常需要接受一个整数参数(信号编号)并且返回void。

        signal()函数的作用是为指定的信号设置处理程序。当进程接收到指定的信号时,会调用相应的处理程序。如果之前已经为该信号设置了处理程序,signal()函数会返回之前设置的处理程序指针;如果没有设置过,将返回SIG_DFL,表示使用默认的信号处理方式。需要注意的是:9号信号不能自定义处理函数。(因为定义了也不起作用)

        如下为一个替换的例子:

#include <iostream>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout<<"获得一个:NO."<<signo<<"信号"<<std::endl;
}

int main()
{
    signal(2,handler);
    while(true)
    {
        std::cout << "i am running~,pid:" <<getpid()<< std::endl;
        sleep(1);
    }
    return 0;
}

        如下,我们通过改变2号信号要调用的函数,从而改变了原来2号信号终止进程的功能:

        接着再看一个对比例子,左边为替换了2号信号调用的函数的进程,右边为正常的进程。可以注意到,当我们两个进程同时跑起来的时候,左边是不能用Ctrl+c终止的,右边确可以,这说明了修改信号只针对于某个进程,也就是说:我们的进程中每一个进程都有一张自己的函数指针数组,数组的下标和信号编号强相关,其中我们可以通过位图来映射这样的数组。

通过raise给自己发信号

   raise函数用于向当前进程发送指定的信号。其函数原型为:

#include<signal.h>
int raise(int sig);

        该函数接受一个参数sig,它是要发送的信号的编号。如果函数执行成功,返回值为0;如果失败,则返回非0值。以下是关于raise函数的一些详细解释:

  1. 功能raise函数的主要作用是允许一个进程给自己发送一个信号。这在某些情况下是有用的,比如当进程需要通知自己发生了某个事件或需要改变自身的行为时。
  2. 等价关系raise(sig)的功能等同于kill(getpid(), sig)。换句话说,raise函数相当于是kill函数的一个特殊形式,其中信号发送者(发送进程)和信号接收者(目标进程)是同一个进程。
  3. 错误处理:如果raise函数不能发送信号(例如,由于权限问题或无效的信号编号),它将返回一个非零错误代码。这与kill函数的错误处理行为类似。
  4. 信号处理:一旦raise函数成功发送了信号,接收进程(即发送进程本身)必须对该信号进行处理。信号的处理方式取决于进程预先设置的处理例程,或者如果没有设置,那么将采用默认的信号处理动作。
  5. 使用场景raise函数通常在需要自我通知或自我中断的场景中使用,比如在多线程程序中,一个线程可能需要通知另一个线程发生了某个事件而不需要其他进程介入。

        如下示例:

#include <iostream>
#include <unistd.h>
#include<signal.h>

void handler(int signo)
{
    std::cout<<"获得一个:NO."<<signo<<"信号"<<std::endl;
}

int main()
{
    signal(2,handler);
   
    while(true)
    {
        std::cout << "i am running~,pid:" <<getpid()<< std::endl;
        sleep(1);
        raise(2);
    }
    return 0;
}

通过abort终止自己

        在Linux系统中,abort函数用于异常终止一个进程。具体来说,abort函数的作用如下:

        函数原型

#include <stdlib.h>
void abort(void);

        当调用该函数时,它会向当前进程发送SIGABRT信号,导致进程异常终止。

  1. 信号处理SIGABRT信号是一个由系统内核发出的信号,它通常用于表示程序出错或需要立即终止的情况。abort函数的实现通常是先取消对SIGABRT信号的阻塞,然后使用raise函数(或等效的机制)向当前进程发送该信号。
  2. POSIX规范:根据POSIX标准,调用abort函数后,进程必须被杀死。这意味着除非在信号处理例程中捕获并处理了SIGABRT信号,否则进程将不可避免地被终止。
  3. 程序示例:在实际编程中,当检测到严重错误或无法恢复的情况时,可以使用abort函数来立即停止程序运行。例如,如果内存分配失败或者程序配置错误,调用abort可以快速结束程序,避免进一步的错误操作。

        综上所述,abort函数是Linux中用于异常终止进程的一个重要函数,它通过发送SIGABRT信号来实现这一目的。在应用程序开发中,合理使用abort函数可以帮助开发者处理不可预见的错误情况,确保程序的稳定性和安全性。

        如下示例:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void handler(int signo)
{
    std::cout<<"获得一个:NO."<<signo<<"信号"<<std::endl;
}

int main()
{
    signal(SIGABRT,handler);
    abort();
    while(true)
    {
        std::cout << "i am running~,pid:" <<getpid()<< std::endl;
        sleep(1);
        
    }
    return 0;
}

具体信号的产生(下一篇内容)

通过终端按键产生信号
调用系统函数向进程发信号
由软件条件产生信号
硬件异常产生信号

 


                   感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       

                                                                        给个三连再走嘛~  

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

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

相关文章

【架构】Docker实现集群主从缩容【案例4/4】

实现集群主从缩容【4/4】 接上一节&#xff0c;在当前机器为4主4从的架构上&#xff0c;减缩容量为3主3从架构。即实现删除6387和6388. 示意图如下&#xff1a; 第一步&#xff1a;查看集群情况&#xff08;第一次&#xff09; redis-cli --cluster check 127.0.0.1:6387roo…

前端性能优化:Vue项目打包后app.xxx.js 和 chunk-vendors.xxx.js 文件太大,导致页面加载时间太长

问题场景&#xff0c;如下图&#xff0c;环境上的 app.js 和chunk-vendors.js 两个文件大小&#xff0c;高达3.4M 和 2M &#xff0c;加载所耗费的时间也很长。 下面说一下如何解决&#xff1a; 1、首先需要安装插件 compression-webpack-plugin&#xff0c;我这里用的是6.1.1…

Java多线程--避免同步机制带来的死锁问题及用Lock锁解决线程安全问题

文章目录 一、死锁&#xff08;1&#xff09;说明&#xff08;2&#xff09;案例1、案例12、案例23、案例3 &#xff08;3&#xff09;诱发死锁的原因及解决方案1、诱发死锁的原因2、避免死锁 二、JDK5.0新特性&#xff1a;Lock(锁)&#xff08;1&#xff09;介绍&#xff08;2…

C++集群聊天服务器 网络模块+业务模块+CMake构建项目 笔记 (上)

跟着施磊老师做C项目&#xff0c;施磊老师_腾讯课堂 (qq.com) 一、网络模块ChatServer chatserver.hpp #ifndef CHATSERVER_H #define CHATSERVER_H#include <muduo/net/TcpServer.h> #include <muduo/net/EventLoop.h> using namespace muduo; using namespace …

Qt6入门教程 15:QRadioButton

目录 一.简介 二.常用接口 三.实战演练 1.径向渐变 2.QSS贴图 3.开关效果 4.非互斥 一.简介 QRadioButton控件提供了一个带有文本标签的单选按钮。 QRadioButton是一个可以切换选中&#xff08;checked&#xff09;或未选中&#xff08;unchecked&#xff09;状态的选项…

深信服技术认证“SCCA-C”划重点:深信服云计算关键技术

为帮助大家更加系统化地学习云计算知识&#xff0c;高效通过云计算工程师认证&#xff0c;深信服特推出“SCCA-C认证备考秘笈”&#xff0c;共十期内容。“考试重点”内容框架&#xff0c;帮助大家快速get重点知识。 划重点来啦 *点击图片放大展示 深信服云计算认证&#xff08…

SG2520CAA汽车用晶体振荡器

爱普生SG2520CAA是简单的封装晶体振荡器&#xff08;SPXO&#xff09;&#xff0c;具有CMOS输出&#xff0c;这款SPXO是汽车和高可靠性应用的理想选择&#xff0c;符合AEC-Q200标准&#xff0c;功耗低&#xff0c;工作电压范围为1.8 V ~ 3.3 V类型&#xff0c;宽工作温度-40℃~…

binder android

文心一言的回答 Binder驱动是Android操作系统中用于进程间通信&#xff08;IPC&#xff09;的机制。它提供了一种高效、跨进程的数据传输方式&#xff0c;使得应用程序的不同组件可以在Android系统上互相通信。 Binder驱动基于Linux内核&#xff0c;其核心组件是一个称为Bind…

git小白之路

初始配置 配置账号密码 git config --list # 设置git的name git config --global user.name "determination" # 设置git的邮箱 git config --global user.email "XXXX.XX.conm" 配置ssh-key ssh-keygen -t rsa -C "usernameemail.com" 添…

活用社交媒体生成二维码:拓展品牌影响力的新时代

社交媒体二维码为品牌在社交媒体平台上的拓展和互动提供了全新的可能性。在这个信息爆炸的时代&#xff0c;如何巧妙地应用社交媒体二维码&#xff0c;成为品牌拓展影响力、与用户建立深度互动的关键。本文将探讨如何精明地应用社交媒体生成二维码&#xff0c;为品牌带来更多的…

来看看思特数字创意产业的科技与狠活儿~ 冰雪大世界图集

01    哈尔滨冰雪大世界以“龙腾冰雪 逐梦亚冬”为主题&#xff0c;为世界各地游客打造一座集冰雪艺术、冰雪文化、冰雪演艺、冰雪建筑、冰雪活动、冰雪体育于一体的冰雪乐园。      02    服务商思特数字创意公司构建“龙腾之韵、雪城乐章、跳动音符、雪映流光”四…

leetcode-35.搜索插入位置

题目 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2示例 2: 输入…

幻兽帕鲁服务器搭建

获取服务器 有如下方法&#xff1a; 阿里云提供现成的幻兽帕鲁服务器&#xff0c;支持一键部署和升级。购买通用服务器或利用已有的主机&#xff0c;配置幻兽帕鲁服务。 第一种可以零代码实现&#xff0c;本文不作赘述&#xff0c;本文主要介绍如何通过已有的Linux服务器实现…

时间序列预测 —— TCN模型

时间序列预测 —— TCN模型 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;在图像处理等领域取得了显著的成就&#xff0c;一般认为在处理时序数据上不如RNN模型&#xff0c;而TCN&#xff08;Temporal Convolutional Network&#xff09;…

基于python+django,我开发了一款药店信息管理系统

功能介绍 平台采用B/S结构&#xff0c;后端采用主流的Python语言进行开发&#xff0c;前端采用主流的Vue.js进行开发。 功能包括&#xff1a;药品管理、分类管理、顾客管理、用户管理、日志管理、系统信息模块。 代码结构 server目录是后端代码web目录是前端代码 部署运行…

Camille-学习笔记-web基础知识

web基础1.系统架构 B/S :Browser/Server 网站 界面层&#xff08;UI&#xff09; 业务逻辑层&#xff08;业务&#xff09; 数据访问层&#xff08;数据库&#xff09; 静态网页&#xff1a;和服务器没有数据交互 动态网页&#xff1a;网页数据可以和服务器进行数据交互 URL…

【数据结构】(四)图

目录 言 图的入门及无向图的实现 1. 图的相关概念 2. 图的相关术语 3. 图的存储结构 3.1 邻接矩阵 3.2 邻接表 3.3 邻接表实现 图的搜索算法 1. 深度优先搜索 1.1 搜索思路 1.2 代码实现 2. 广度优先搜索 2.1 搜索思路 2.2 代码实现 后记 言 数据结构分为逻辑结…

vscode 如何修改c/c++格式化风格,大括号不换行

在Visual Studio Code&#xff08;VSCode&#xff09;中&#xff0c;若要修改C代码格式化的风格以实现大括号不换行&#xff0c;通常会借助于插件C/C扩展中的ClangFormat配置。以下是具体的步骤&#xff1a; 确保已安装了C/C扩展&#xff1a; 打开VSCode的扩展市场&#xff08;…

【飞书小技巧】——飞书文档转 markdown 详细教程

飞书文档转 markdown 详细教程 基于项目:https://github.com/Wsine/feishu2md 如何使用 在线版 访问 https://feishu2md.onrender.com/ 粘贴文档链接即可&#xff0c;文档链接可以通过 分享 > 开启链接分享 > 复制链接 获得。 点击下载之后,会提示 Please wait. It ma…

回归预测 | Matlab基于POA-LSSVM鹈鹕算法算法优化最小二乘支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于POA-LSSVM鹈鹕算法算法优化最小二乘支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于POA-LSSVM鹈鹕算法算法优化最小二乘支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于POA-LSSVM…