【Linux进程信号】Linux信号产生机制详解:掌握系统通信的关键

news2024/11/26 1:25:49

📝个人主页🌹:Eternity._
⏩收录专栏⏪:Linux “ 登神长阶 ”
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀Linux进程信号

  • 📒1. 信号入门
  • 📜2. 信号捕捉初识
  • 📚3. 信号的产生
    • 🌊通过终端按键产生信号
    • 🍂调用系统函数向进程发信号
    • 🌸由软件条件产生信号
    • 🌵硬件异常产生信号
  • 📖4. 总结


🔍前言:在Linux操作系统中,信号(Signal)是一种重要的进程间通信机制,它允许一个进程向另一个进程发送异步通知。这些通知可以是简单的消息,如用户按下了中断键(如Ctrl+C),也可以是复杂的系统事件,如除零错误或定时器到期。信号的产生和处理是Linux系统编程中的一个关键方面,对于理解和优化系统行为至关重要

本文旨在深入探讨Linux中信号的产生机制。我们将从信号的基本概念出发,逐步解析信号的来源、触发条件。通过本文的学习,你将能够了解信号在Linux内核中的实现原理,掌握如何编写代码来捕获和处理信号,以及如何利用信号来实现进程间的同步和通信

信号在Linux系统中的应用非常广泛,从简单的用户中断到复杂的系统监控和管理,都离不开信号的支持。因此,掌握信号的产生和处理机制,对于提高Linux系统编程能力、优化系统性能以及开发高效、稳定的系统应用程序具有重要意义

让我们一起踏上这段探索之旅,共同揭开Linux信号产生机制的神秘面纱!


📒1. 信号入门

信号概念:

在操作系统中,信号是一种异步通知机制,用于在进程之间或同一进程的不同线程之间传递信息。这种机制允许一个进程(或线程)在不影响其正常执行流程的情况下,通知另一个进程(或线程)某个事件的发生。信号在Linux和其他类Unix操作系统中扮演着非常重要的角色

在生活中例如:我们在网上购物时,即便快递没有到来,我们也知道快递来临时,该怎么处理快递。也就是能 识别快递,但是当快递到达的时候,我们也没有立马过去取快递,也就是取快递的行为并不是一定要立即执行,可以理解成 在合适的时候去取,在收到通知,再到我们拿到快递期间,是有一个时间窗口的,在这段时间,并没有拿到快递,但是我们知道有一个快递已经来了。本质上是 记住了有一个快递要去取,当我们时间合适,顺利拿到快递之后,就要开始处理快递了。而处理快递一般方式有三种:1. 执行默认动作(打开快递)2. 执行自定义动作(给别人的礼物)3. 忽略快递(不急着用,先丢一边),快递到来的整个过程,对你来讲是 异步的,你不能准确断定快递员什么时候给你打电话。

在技术应用角度:用户输入命令,在Shell下启动一个前台进程,用户按下Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程,前台进程因为收到信号,进而引起进程退出

进程就是我们,操作系统就是快递员,信号就是快递


信号的基本概念:

  • 异步性:信号是异步事件,可以在任何时候、由任何进程(包括内核进程和用户进程)发送给另一个进程
  • 通知性:信号的主要目的是通知接收进程某个事件的发生,而不是传递数据。虽然信号可以携带一些简单的信息(如信号编号),但通常不用于传输大量数据
  • 处理机制:每个信号都有一个默认的处理程序,通常是由操作系统提供的。但进程也可以指定自己的信号处理程序来替代默认处理

注意事项:

  • Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程
  • Shell 可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生的信号
  • 前台进程在运行过程中用户随时可能按下 Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步

系统信号列表:

指令:kill -l

在这里插入图片描述
实际上每个进程都有一张自己的函数指针数组,数组的下标就和信号编号强相关

这些信号各自在什么条件下产生,默认的处理动作是什么
在signal(7)中都有详细说明: man 7 signal

在这里插入图片描述


信号处理常见方式:

  • 忽略此信号
  • 执行该信号的默认处理动作
  • 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉一个信号

📜2. 信号捕捉初识

信号是可以被自定义捕捉的,siganl函数就是来进行信号捕捉的

代码示例:

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

using namespace std;

void headler(int signo)
{
    cout << "收到一个" << signo << "号信号" << endl;
}

int main()
{
    signal(2, headler);

    while(1)
    {
        cout << "running ... pid: " << getpid() << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

注意:并不是所有的信号都能捕捉,比如SIGKILL


📚3. 信号的产生

在每个进程的PCB中,都会有一个信号位图,由操作系统修改其中的比特位(0->1),完成信号的发送,发送信号只能由操作系统发送


🌊通过终端按键产生信号

  • Ctrl+C:当用户在前台进程运行时按下Ctrl+C组合键,会产生一个SIGINT(中断信号),通常用于终止前台进程。
  • Ctrl+Z:当用户按下Ctrl+Z组合键时,会产生一个SIGTSTP(停止信号),用于暂停前台进程的执行,并将其置于停止状态。
  • Ctrl+\:当用户按下Ctrl+\组合键时,会产生一个SIGQUIT(退出信号),用于终止进程并生成核心转储文件(Core Dump),这有助于开发者事后调试和查找错误。

Core Dump:

Core Dump:用于在进程因某些信号而异常终止时,将其当时的内存状态记录下来,并保存在一个文件中。一般为core.pid的形式,这个文件通常被称为core dump文件或核心转储文件

查看Core Dump是否开启:

指令:ulimit -a
如果返回值为0,则表示Core Dump被禁用;如果返回值为unlimited或具体的大小值,则表示Core Dump被启用,并设置了最大文件大小

在这里插入图片描述


开启Core Dump:

指令:ulimit -c 大小
Core Dump是默认关闭的,要想实现Core Dump的持久化开启,需要更改配置文件

在这里插入图片描述


Core Dump文件:

在这里插入图片描述


查看Core Dump文件:

  • 可以使用GDB(GNU Debugger)等调试工具来加载Core Dump文件,并查看程序崩溃时的现场信息,以便进行调试和错误定位

🍂调用系统函数向进程发信号

系统调用是操作系统提供给用户程序与硬件进行交互的一组函数接口。通过系统调用,用户程序可以请求操作系统执行某些操作

在这里插入图片描述


kill:

kill:kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号

代码示例:

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

using namespace std;

// 输入准则
static void Usage(const string &proc)
{
    cout << "\nUsage: " << proc << "-signumber process" << endl;
}

void headler(int signo)
{
    cout << "收到一个" << signo << "号信号" << endl;
}

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(0);
    }

    // "-"
    int signumber = stoi(argv[1]+1);
    int processid = stoi(argv[2]);

    kill(processid, signumber);

    return 0;
}

在这里插入图片描述


raise:

raise:用于向当前进程发送信号。与kill不同,raise不需要指定进程ID,因为它默认作用于当前进程

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

using namespace std;

// raise
void headler(int signo)
{
    cout << "get a signo: " << signo << endl;
    sleep(1);
}

int main()
{
    signal(2, headler);

    while(1)
    {
        raise(2);
    }
    return 0;
}

在这里插入图片描述


abort:

abort:用于向当前进程发送SIGABRT信号,通常用于程序遇到无法恢复的错误时主动终止执行

代码示例:

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

using namespace std;

// abort
void headler(int signo)
{
    cout << "get a signo: " << signo << endl;
}

int main()
{
    signal(SIGABRT, headler);

    abort();

    while(1)
    {
        cout << "running ... " << endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述


🌸由软件条件产生信号

由软件条件产生信号,通常指的是在软件应用程序中,根据某些特定的条件或逻辑判断来触发或生成信号

  • 定时器到期:通过调用alarm函数设置一个定时器,当定时器到期时会产生SIGALRM信号
  • 非法内存访问:如访问未分配的内存或越界访问数组等,会产生SIGSEGV(段错误)信号
  • 除零错误:进行浮点数除法运算时,如果除数为零,会产生SIGFPE(浮点异常)信号

在这里插入图片描述
在这里插入图片描述


void headler(int signo)
{
    cout << "get a signo: " << signo << endl;
    sleep(1);
}

int main()
{
    signal(8, headler);

    int x = 10; 
    int y = 0;
    int z = x / y;

    return 0; 
}

在这里插入图片描述

当我们捕捉一个除零错误的信号时,我们明明没有循环结构,但是它一直在循环打印,其实是,我们捕捉信号时,进程并没有被杀掉,它就一直在调度,异常一次就发送一次信号,所以我们在捕捉信号时,都要进行终止进程


定时器:

alarm:用于设置一个定时器,当定时器到期时会向进程发送一个SIGALRM信号

在这里插入图片描述
在这里插入图片描述

边输出边打印涉及到访问外设,效率会低,而我们只做一次打印效率就会更快,所以外设其实是很慢的


alarm的返回值是它所剩余的时间

代码示例:

int n = 0;

void headler(int signo)
{
    n = alarm(0);
    cout << "result: " << n << endl;
    //cout << "get a signo: " << signo << " alarm: " << cnt << endl;
    exit(0);
}

int main()
{
    signal(14, headler);
    
    cout << "pid: " << getpid() << endl;
    alarm(30);

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

在这里插入图片描述

操作系统中的时间:

  • 1.所有用户的行为,都是以进程的形式在OS中表现的
  • 2.操作系统只要把进程调度好,就能完成所有的用户任务
  • 3.CMOS,周期性的,高频率的,向CPU发送时钟中断

🌵硬件异常产生信号

硬件异常产生信号是指硬件设备在运行时遇到错误或异常情况时向操作系统发送信号

例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程


📖4. 总结

随着我们对Linux中信号产生的深入学习,我们已逐渐揭开了这一进程间通信机制的神秘面纱。从信号的起源、类型到其在系统中的传递和处理,每一个细节都充满了智慧与巧妙的设计

信号的魅力在于它的简洁与高效。作为进程间异步通信的桥梁,信号无需复杂的协议或数据结构,仅凭一个数字编号就能传递丰富的信息。这种设计不仅降低了系统的开销,还提高了通信的灵活性

然而,信号的学习之旅并未结束。随着技术的不断进步和Linux系统的广泛应用,信号在进程管理、资源控制以及系统安全等方面的作用将越来越重要。掌握信号的产生和处理机制,将使我们能够更好地应对各种复杂的系统场景,为系统的稳定运行提供有力保障

最后,让我们以一颗好奇和敬畏的心,继续这段信号之旅!

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

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

相关文章

Windows应急响蓝安服面试

Windows应急响应 蓝队溯源流程 学习Windows应急首先要站在攻击者的角度去学习一些权限维持和权限提升的方法.,文章中的方法其实和内网攻防笔记有类似l红队教你怎么利用 蓝队教你怎么排查 攻防一体,应急响应排查这些项目就可以 端口/服务/进程/后门文件都是为了权限维持,得到s…

linux安装hadoop

目录 jdk安装配置 hadoop安装 hadoop配置 配置ssh免密登录 启动hadoop 实现文件上传下载 eclipse安装配置 jdk安装配置 1、删除centos自带的jdk yum list installed | grep java yum remove *openjdk* 2、下载jdk安装包 wget --no-check-certificate https://repo.h…

InternVid:用于多模态视频理解与生成的大规模视频-文本数据集 | ICLR Spotlight

InternVid 是一个开源的大规模视频-文本数据集&#xff0c;旨在促进视频理解和生成任务的发展&#xff0c;由上海人工智能实验室与南京大学、中国科学院等单位联合发布&#xff0c;相关的工作已经被ICLR2024接收。它包含超过 700 万个视频&#xff0c;总时长近 76 万小时&#…

位操作位操作位操作

呵呵哈哈哈哈哈哈哈哈哈和哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈

MySQL—视图

前言&#xff1a; 视图是一个虚拟的表&#xff0c;是基于一个或多个基本表或其他视图的查询结果集。视图本身不占据物理储存空间&#xff0c;仅仅只是一个查询的逻辑表示&#xff0c;物理上依赖于数据表的数据。 视图具有简单&#xff0c;安全&#xff0c;逻辑数据独立&#…

CST软件优化超表面--- 偏振片- 线圆极化转换,天线阵任务,远场算轴比AR

本期我们继续看线极化转圆极化。本案例是个三层结构&#xff0c;比单层的偏振片有更宽的频率和更少的反射。我们将利用CST的天线阵列任务中的单元任务&#xff0c;加上优化器优化&#xff0c;使偏振片在多个入射角、多个频率&#xff0c;S11反射都够小&#xff0c;AR都够圆。 …

Spark-RDD的宽窄依赖以及Shuffle优化

目录 RDD宽窄依赖的区别 DAG有向无环图 窄依赖 宽依赖 shuffle过程 Shuffle介绍 Spark优化-避免shuffle RDD宽窄依赖的区别 窄依赖 每个父RDD的一个Partition最多被子RDD的一个Partition所使用 mapflatMapfilter宽依赖 一个父RDD的Partition会被多个子RDD的Partition所使…

LCD补充

LCD补充 目录 LCD补充 tip:随着我们学的越来越多&#xff0c;代码长度越来越长&#xff0c;编译越来越慢&#xff0c;有没有超过内存是我们比较关心的一件事&#xff0c;通过以下方法可以实时看到写的代码的大小 回顾LCD LCD补充功能 -- 1、有关在LCD上显示动图&#xff…

Python库matplotlib之九

Python库matplotlib之九 动画ArtistAnimation构造器成员函数应用例子 动画 Matplotlib基于其绘图功能&#xff0c;还提供了一个使用动画模块&#xff0c;生成动画的接口。动画是一系列帧&#xff0c;其中每个帧对应于图形上的一个图。 Matplotlib使用两个类来实现动画&#x…

ordinaryroad-barrage-fly wsl部署记录

系统&#xff1a;win11 wsl版本&#xff1a;wsl2 Linux&#xff1a;Ubuntu 22.04.4 LTS 文档&#xff1a;https://barragefly.ordinaryroad.tech/deploy/#_2-1-docker-compose docker相关的内容自己事先安装好 git clone https://github.com/OrdinaryRoad-Project/ordinaryr…

TensorBoard

1、概念 TensorBoard可以看作是一个“训练监控仪表盘”&#xff0c;可以 将训练过程中的数据可视化&#xff0c;让你通过图表直观地看到模型的表现&#xff0c; 识别问题&#xff0c;并进行调试和优化。 TensorFlow是用来训练模型的深度学习框架&#xff0c;在使用tensorflo…

基于SpringBoot+Vue的疫情物资管理系统(带1w+文档)

基于SpringBootVue的疫情物资管理系统(带1w文档) 基于SpringBootVue的疫情物资管理系统(带1w文档) 本课题研究和开发疫情物资管理系统管理系统&#xff0c;让安装在计算机上的该系统变成管理人员的小帮手&#xff0c;提高疫情物资管理系统信息处理速度&#xff0c;规范疫情物资…

内网wordpress更换IP后无法访问的解决办法

一、现象 一台装有wordpress的台式机&#xff0c;从一个校区移到了另一个校区&#xff0c;更换了IP地址&#xff0c;导致无法正常访问。 二、分析 安装wordpress的时候里面的ip&#xff08;或域名&#xff09;都已固定。安装好后&#xff0c;内网通过IP访问&am…

基于Maven 运行OpenRewrite的快速示例

本篇介绍一个基于Maven 运行OpenRewrite 的快速示例&#xff0c;展示了如何在Maven项目中使用OpenRewrite 进行代码重构。 本篇达成的效果是使用OpenRewrite 对源码自动格式化。 达成效果期望 项目中有一个类AutoFormatDemo &#xff0c;类的代码如下 public class AutoFor…

ubuntu24 root用户修改密码 ubuntu新系统没有创建root用户

ubuntu 系统在虚拟机新建一个ubuntu24&#xff0c;但是在配置系统时候&#xff0c;并没有配置root密码&#xff0c;只是新增了一个自定义账号于密码&#xff0c;在创建好后&#xff0c;可以登录系统&#xff0c;设置root密码~ 1. ubuntu系统初始化后&#xff0c;登录自建账号 …

Nullinux:一款针对Linux操作系统的安全检测工具

关于Nullinux Nullinux是一款针对Linux操作系统的安全检测工具&#xff0c;广大研究人员可以利用该工具针对Linux目标设备执行网络侦查和安全检测。 该工具可以通过SMB枚举目标设备的安全状况信息&#xff0c;其中包括操作系统信息、域信息、共享信息、目录信息和用户信息。如…

C# 结构和类

要点&#xff1a; 1、结构概述 2、结构的使用 一 为什么需要结构 问题&#xff1a; System.Drawing.Color有很多颜色值&#xff0c;它是一个枚举吗&#xff1f; 正常人眼可分辨的颜色种类可达几十万种以上 Color提供使用RGB值返回颜色的方法 FromArgb() System.Drawing.Col…

LabVIEW开关磁阻电机特性测量系统

基于LabVIEW软件和特定硬件组件的开关磁阻电机&#xff08;SRM&#xff09;特性测量系统&#xff0c;结合多功能数据采集卡&#xff0c;统能够准确地测量并分析SRM的电磁特性&#xff0c;从而支持电机模型的精确建立和性能优化。 项目背景 在工业生产和家用电器领域&#xff0…

电子取证新视角:USB键盘流量提取密码方法研究与实现

0x01 引言 在当今数字化时代&#xff0c;USB设备的广泛使用使得信息安全和电子取证领域面临着新的挑战与机遇。特别是USB键盘&#xff0c;作为一种常见的输入设备&#xff0c;其流量中可能包含用户输入的敏感信息&#xff0c;如密码和其他私人数据。因此&#xff0c;研究USB键…

数据治理:制造企业转型的关键要素与战略需求

制造业&#xff0c;作为国民经济的主体&#xff0c;是立国之本、兴国之器、强国之基。从工业文明的曙光初现&#xff0c;到今日全球化的激烈竞争&#xff0c;始终昭示着一个真理&#xff1a;没有强大的制造业&#xff0c;就没有国家和民族的强盛。 为全面推进制造强国建设&…