Linux 进程信号初识

目录

0.前言

1.什么是信号

1.1生活中的信号

1.2 OS中的信号

2.认识信号

2.1信号概念

2.2查看信号

2.3 signal函数

2.4代码示例

3. 信号处理方式

3.1 忽略信号

3.2 默认处理

3.3 自定义处理

4.小结


(图像由AI生成) 

0.前言

在之前的学习中,我们介绍了 Linux 进程间通信 的多种方式,如管道、消息队列、共享内存等。接下来,我们将关注另一种进程间的重要机制:信号。信号是 Linux 系统中一种重要的异步通信手段,用于通知进程发生了某些事件,比如用户按下 Ctrl+C 或操作系统的某些异常情况。在本文中,我们将从基础知识出发,一步步认识信号的作用和处理方式。

1.什么是信号

1.1生活中的信号

生活中,我们常常通过“信号”获取信息并采取行动。例如:

外卖通知
你通过手机订了一份外卖。以下是外卖到来过程中的几个场景:

  1. 下单后等待外卖送达:你知道外卖会来,但不知道具体什么时候会送到。此时,你继续忙自己的事情,比如工作、学习,甚至小憩。
  2. 接到送餐员的通知:手机收到送餐员的短信或电话通知时,你立刻知道外卖到了。但如果你正在开会,可能会让送餐员稍等几分钟。
  3. 处理外卖
    • 你亲自下楼取外卖,这相当于采取了默认动作。
    • 你让同事帮忙取外卖,类似于自定义动作。
    • 外卖到后,你暂时不处理,继续工作,这等于忽略了外卖。

整个过程中,“外卖通知”就是一种“信号”。

  • 它是异步的:你不知道通知会在什么时候发来。
  • 它需要处理:当收到通知时,你决定如何响应。
  • 它可能被忽略:你可以选择不处理这个信号(比如延后取外卖)。

这与操作系统中的信号非常相似,信号是用于通知进程发生了某种事件,而处理与否、如何处理由程序决定。

1.2 OS中的信号

信号在操作系统中的概念
在操作系统中,信号是用来通知进程发生特定事件的一种机制。例如:

  • 用户按下 Ctrl+C 中断程序。
  • 某些硬件或软件事件(如定时器超时、文件访问异常)触发信号。

举例:死循环程序与 Ctrl+C 中断

让我们用一个简单的死循环程序来演示信号的基本作用:

#include <stdio.h>
#include <unistd.h>int main() {while (1) {printf("Running... Press Ctrl+C to stop.\n");sleep(1);}return 0;
}
  1. 运行程序:执行该程序后,它会不断输出 Running... 并每隔一秒更新一次。
  2. 按下 Ctrl+C:此时,操作系统会向程序发送一个 SIGINT 信号(中断信号)。
  3. 响应信号:程序收到信号后,会执行默认的信号处理动作:终止程序。

以下是一次完整的信号交互过程:

  • 信号发送:按下 Ctrl+C,操作系统检测到键盘事件并发送 SIGINT 信号给程序。
  • 信号处理:程序执行默认动作,终止运行。
  • 异步性:信号的到来是非确定的,程序无法预测用户何时按下 Ctrl+C

总结:

  • 信号在操作系统中是一种异步事件通知机制。
  • 它类似于生活中的通知机制,可以在某个事件发生时通知进程并交由其处理。

2.认识信号

2.1信号概念

信号是操作系统中的一种进程间通信机制,用于通知进程发生了某些事件。
它的核心特性包括:

  1. 异步性:信号的发送和接收是异步的,进程无法预知信号何时到达。
  2. 触发性:信号通常与特定事件相关联,如用户输入、进程状态变化、硬件异常等。
  3. 有限性:信号的传递只携带类型信息(如 SIGINTSIGKILL),而不包括详细的数据。

信号的生命周期:

  1. 发送信号:由内核或进程触发。
  2. 等待处理:信号到达目标进程时,可能暂时被挂起。
  3. 信号处理:进程可以选择处理信号、忽略信号或采取默认操作。

信号类似于生活中的通知,例如系统提示电量不足(异步)、提醒需要充电(触发),但没有告知具体电量值(有限性)。

2.2查看信号

Linux 系统提供了多个标准信号,可以通过 kill -l 命令查看完整列表。

信号分类:

  1. 通用信号(1-31):常用于进程的基本控制,例如中断、终止、挂起等。

    • SIGHUP:挂起信号。
    • SIGINT:中断信号(如按下 Ctrl+C)。
    • SIGKILL:强制终止信号。
    • SIGTERM:终止信号,可被捕获和处理。
    • SIGSEGV:非法内存访问。
  2. 实时信号(34-64):支持更高的灵活性和用户定义,用于实时任务通信。

    • SIGRTMIN:最小的实时信号。
    • SIGRTMAX:最大的实时信号。

示例命令:

kill -l

输出如下:

 

2.3 signal函数

函数简介

signal 是一个 ANSI C 标准函数,用于设置进程对特定信号的处理方式。通过该函数,可以定义信号处理程序,或选择默认行为、忽略信号。

函数原型

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

    • signum:信号编号,例如 SIGINT(中断信号)。
    • handler:指定的信号处理方式,可以是以下三种之一:
      • SIG_IGN:忽略信号。
      • SIG_DFL:采用信号的默认处理方式。
      • 自定义处理函数的地址。
  • 返回值:

    • 成功时返回之前的信号处理方式(SIG_IGNSIG_DFL 或处理函数地址)。
    • 失败时返回 SIG_ERR,同时设置 errno 以说明错误原因。

函数行为

  • 当进程接收到信号 signum 时,signal 函数会决定如何处理:
    • 忽略信号SIG_IGN):直接跳过信号处理。
    • 默认处理SIG_DFL):执行信号的系统默认行为(如终止进程)。
    • 自定义函数:调用程序员定义的函数处理信号。
  • 特殊信号:SIGKILLSIGSTOP 无法被捕获或忽略。

注意事项

  • 不同 UNIX 系统对 signal 的实现存在差异,Linux 的行为在历史版本中也有变化。
  • 推荐使用 sigaction 替代 signal,因为它提供了更强的功能和一致性。

2.4代码示例

以下代码演示了如何使用 signal 函数捕获 SIGINT 信号,并自定义处理方式:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>// 自定义信号处理函数
void handle_sigint(int signum) {printf("Caught SIGINT (signal number: %d). Exiting gracefully...\n", signum);// 释放资源并退出_exit(0);
}int main() {// 使用 signal 函数捕获 SIGINT 信号if (signal(SIGINT, handle_sigint) == SIG_ERR) {perror("Error setting signal handler");return 1;}printf("Press Ctrl+C to trigger SIGINT...\n");// 无限循环,等待信号while (1) {printf("Running...\n");sleep(1);}return 0;
}

代码分析

  1. 自定义信号处理函数

    • handle_sigint 是一个函数,接收信号编号作为参数。
    • SIGINT 信号到达时,程序会调用该函数,输出提示信息并优雅退出。
  2. 设置信号处理

    • signal(SIGINT, handle_sigint) 指定 SIGINT 信号的处理方式为调用 handle_sigint 函数。
    • 如果 signal 调用失败,返回 SIG_ERR 并设置 errno,在此处打印错误信息并退出程序。
  3. 等待信号

    • 程序进入无限循环,每秒打印一次 Running...,等待用户按下 Ctrl+C 触发 SIGINT 信号。

运行结果

  • 正常运行时,程序会不断输出 Running...
  • 当按下 Ctrl+C 时,程序捕获到 SIGINT 信号,调用 handle_sigint 函数,输出提示并退出。

3. 信号处理方式

在 Linux 系统中,当进程接收到信号时,可以采用三种不同的方式处理信号:忽略默认处理自定义处理。进程对信号的处理方式决定了程序如何响应特定事件或异常。

3.1 忽略信号

进程可以选择忽略某些信号,这意味着即使信号被发送到进程,它也会被直接丢弃,进程的行为不会受到任何影响。

  • 常用场景

    • 忽略某些不重要的信号,如 SIGPIPE(管道断裂信号),避免进程因无关紧要的错误而终止。
    • 对用户输入的某些信号(如 SIGINT)做出特定策略,暂时忽略信号而不中断当前任务。
  • 代码示例

#include <signal.h>
#include <stdio.h>
#include <unistd.h>int main() {// 忽略 SIGINT 信号signal(SIGINT, SIG_IGN);printf("SIGINT signal is ignored. Try pressing Ctrl+C.\n");while (1) {printf("Running...\n");sleep(1);}return 0;
}

运行此程序后,按下 Ctrl+C 时进程不会终止,因为 SIGINT 信号被忽略了。

3.2 默认处理

系统为每种信号定义了默认的处理方式,进程可以直接使用这些默认动作:

  • 常见默认行为

    • 终止进程:SIGTERMSIGKILL
    • 生成核心转储文件并终止进程:SIGSEGVSIGABRT
    • 停止进程:SIGSTOP
  • 特点

    • 简单快捷。
    • 适用于无需自定义处理逻辑的场景。
  • 代码示例

#include <signal.h>
#include <stdio.h>
#include <unistd.h>int main() {printf("Default behavior for SIGINT. Press Ctrl+C to terminate.\n");while (1) {printf("Running...\n");sleep(1);}return 0;
}

运行此程序时,按下 Ctrl+C 会发送 SIGINT 信号,进程将采用默认行为:立即终止。

3.3 自定义处理

通过定义信号处理函数,程序可以指定如何响应某些信号。这种方式为程序提供了灵活性,可以在信号到达时执行特定逻辑。

  • 常见用途

    • 释放资源(文件句柄、内存)并优雅退出。
    • 记录日志以便诊断问题。
    • 延迟或改变信号的处理逻辑。
  • 代码示例

#include <signal.h>
#include <stdio.h>
#include <unistd.h>// 自定义信号处理函数
void custom_handler(int signum) {printf("Caught signal %d. Cleaning up before exiting...\n", signum);// 释放资源// 退出程序_exit(0);
}int main() {// 捕获 SIGINT 信号并设置自定义处理函数signal(SIGINT, custom_handler);printf("Custom handler for SIGINT. Press Ctrl+C.\n");while (1) {printf("Running...\n");sleep(1);}return 0;
}

运行此程序后,按下 Ctrl+C 时会触发自定义的信号处理逻辑,打印提示信息并优雅退出。

4.小结

信号是 Linux 系统中重要的进程间通信机制,具有异步性和灵活性。在本篇博客中,我们从生活中的类比入手,深入了解了信号的概念、种类及其处理方式,包括忽略信号、使用默认处理、以及自定义处理函数。通过实际代码示例,我们掌握了如何使用 signal 函数捕获并处理信号,为开发更高效、更健壮的 Linux 应用程序奠定了基础。

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

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

相关文章

SpringBoot(二十五)SpringBoot集成JRebel实现热更新

今天来安装一个IDEA代码热更新的插件,一个神器。 我们之前也为IDEA配置了热更新,使用的是spring-boot-devtools插件。具体请移步《SpringBoot(一)创建项目及配置IDEA热更新》 上边这个热更新对于单模块项目是没有问题的,但是对于多模块项目可能就无能无能为力了,而且,随…

MATLAB中的绘图技巧

MATLAB作为一种强大的科学计算软件&#xff0c;不仅可以进行数据分析和模拟&#xff0c;还具有出色的绘图功能。本文介绍若干在MATLAB中绘图的技巧和方法&#xff0c;帮助使用者更好地呈现数据和结果 文章目录 基本绘图函数高级绘图技巧三维绘图动态绘图绘图工具结语 基本绘图函…

java八股-AQS,Reentrantlock

什么是AQS&#xff1f; 难度&#xff1a;★★★☆☆ 考频&#xff1a;★★★☆☆ 注意这个队列是双向队列&#xff0c;每次有线程释放锁了之后&#xff0c;会有下一个线程来&#xff0c;以及队列头元素&#xff0c;如果设置的是公平锁&#xff0c;那么是等了很久的头元素先获…

python——模块 迭代器 正则

一、python模块 先创建一个 .py 文件&#xff0c;这个文件就称之为 一个模块 Module。 使用模块的优点&#xff1a; 模块化编程&#xff0c;多文件编程 1.2 模块的使用 1.2.1 import语句 想要B.py文件中&#xff0c;使用A.py文件&#xff0c;只需要在B.py文件中使用关键字…

STL之mapset|AVL树

STL之map&set|AVL树 set&map搜索二叉树实现代码 set的使用map的使用set&map的模拟实现&#xff08;见红黑树篇&#xff09; AVL树AVL树的模拟实现 set&map 前言&#xff1a;stl库中set和map的底层都是红黑树&#xff0c;一种平衡搜索二叉树&#xff0c;是我下…

使用阿里云快速搭建 DataLight 平台

使用阿里云快速搭建 DataLight 平台 本篇文章由用户 “闫哥大数据” 分享&#xff0c;B 站账号&#xff1a;https://space.bilibili.com/357944741?spm_id_from333.999.0.0 注意&#xff1a;因每个人操作顺序可能略有区别&#xff0c;整个部署流程如果出现出入&#xff0c;以…

OceanBase 分区表详解

1、分区表的定义 在OceanBase数据库中&#xff0c;普通的表数据可以根据预设的规则被分割并存储到不同的数据区块中&#xff0c;同一区块的数据是在一个物理存储上。这样被分区块的表被称为分区表&#xff0c;而其中的每一个独立的数据区块则被称为一个分区。 如下图所示&…

代码随想录算法训练营第三十八天 | 322.零钱兑换 279.完全平方数 139.单词拆分 多重背包以及背包总结

LeetCode 322.零钱兑换&#xff1a; 文章链接 题目链接&#xff1a;322.零钱兑换 思路&#xff1a; 首先分析题目&#xff0c;每种硬币的数量是无限的&#xff0c;因此为完全背包问题&#xff1b;又要求返回的是最少硬币个数&#xff0c;因此与组合数/排列数无关&#xff0c…

计算机网络WebSocket——针对实习面试

目录 计算机网络WebSocket什么是WebSocket&#xff1f;WebScoket和HTTP协议的区别是什么?说明WebSocket的优势和使用场景&#xff1f;说明WebSocket的建立连接的过程&#xff1f; 计算机网络WebSocket 什么是WebSocket&#xff1f; WebSocket是一个网络通信协议&#xff0c;提…

在Ubuntu 24.04 LTS上安装飞桨PaddleX

前面我们介绍了《在Windows用远程桌面访问Ubuntu 24.04.1 LTS》本文接着介绍安装飞桨PaddleX。 PaddleX 3.0 是基于飞桨框架构建的一站式全流程开发工具&#xff0c;它集成了众多开箱即用的预训练模型&#xff0c;可以实现模型从训练到推理的全流程开发&#xff0c;支持国内外多…

LM2 : A Simple Society of Language Models Solves Complex Reasoning

文章目录 题目摘要简介相关工作方法论实验结果结论局限性 题目 LM2&#xff1a;简单的语言模型社会解决复杂推理问题 论文地址&#xff1a;https://aclanthology.org/2024.emnlp-main.920/ 项目地址&#xff1a; https://github.com/LCS2-IIITD/Language_Model_Multiplex 摘要…

(三十三)队列(queue)

文章目录 1. 队列&#xff08;queue&#xff09;1.1 定义1.2 函数1.3 习题1.3.1 例题&#xff08;周末舞会&#xff09; 2. 双向队列&#xff08;deque&#xff09;2.1 定义2.2 函数2.3 题目2.3.1 例题&#xff08;打BOSS&#xff09; 1. 队列&#xff08;queue&#xff09; 队…

web——upload-labs——第二关

MIME验证 MIME&#xff08;Multipurpose Internet Mail Extensions&#xff09;验证是指在互联网传输中&#xff0c;通过检查数据的MIME类型来确保数据格式的正确性和安全性。MIME最初是为了扩展电子邮件的功能&#xff0c;让邮件支持多种格式&#xff0c;如文本、图片、音频等…

Vue3 -- 集成sass【项目集成5】

集成sass&#xff1a; 看过博主的 配置styleLint工具应该已经安装过 sass sass-loader 了&#xff0c;所以我们只需要加上我们的 lang"scss"即可。 <style scoped lang"scss"></style>给项目添加全局样式文件&#xff1a; 在src文件夹下创建…

【Web前端】Promise的使用

Promise是异步编程的核心概念之一。代表一个可能尚未完成的操作&#xff0c;并提供了一种机制来处理该操作最终的成功或失败。具体来说&#xff0c;Promise是由异步函数返回的对象&#xff0c;能够指示该操作当前所处的状态。 当Promise被创建时&#xff0c;它会处于“待定”&a…

EI检索!2024年大数据与数据挖掘会议(BDDM 2024)全解析!

第二届大数据与数据挖掘国际会议&#xff08;BDDM 2024&#xff09;将于2024年12月13-15日在武汉举行&#xff0c;已启动第二轮征稿&#xff0c;截稿2024年11月30日。邀请学者探讨大数据与数据挖掘进展&#xff0c;可在线投稿及AC学术中心查看详情。 大会官网&#xff1a;www.i…

基于java+ssm+Vue的校园美食交流系统设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven mysql5.7或8.0等等组成&#x…

关于 MSVCP110.dll 缺失的解决方案

背景&#xff1a;之前使用 PR&#xff08;Adobe Premiere&#xff09; 从来没有遇到过这样的问题。今天重装系统后&#xff08;window 10&#xff09;&#xff0c;想要重新安装以前的软件时&#xff0c;遇到了以下 DLL 文件缺失的错误。 解决方案&#xff1a; 可以到微软官网的…

Python小游戏27——飞翔的小鸟

首先&#xff0c;你需要确保已经安装了Pygame库。如果还没有安装&#xff0c;可以通过以下命令进行安装&#xff1a; 【bash】 pip install pygame 游戏的代码&#xff1a; 【python】 import pygame import random # 初始化Pygame pygame.init() # 设置屏幕大小和标题 screen_…

【Three.js基础学习】24. shader patterns

前言 课程回顾: ShaderMaterial 这里用的是着色器材质 所以顶点和片段着色器就不需要像原始着色器那样添加需要的属性 然后写 片段着色器需要属性 &#xff1a; 顶点 属性 -》变化 -》 片段中 顶点中的属性不需要声明 只需要声明传送的变量 例如 varying vec vUv; vUv uv; 补充…