[Linux系统编程]进程信号

进程信号

  • 1. 信号入门
    • 1.1 信号基本概念
    • 1.2 技术应用角度的信号
  • 2. 信号的产生
    • 2.1 通过终端按键(如键盘)产生信号
    • 2.2 通过异常产生信号
    • 2.3 调用系统函数向进程发信号
    • 2.4 由软件条件产生信号
    • 2.5 总结
  • 3. 阻塞信号
    • 3.1 信号其他相关常见概念
    • 3.2 内核中的信号表示
    • 3.3 sigset_t
      • 3.3.1 信号集(sigset_t)
      • 3.3.2 信号集的两种主要用途
      • 3.3.3 sigset_t 的工作原理
      • 3.3.4 信号集的内核实现
    • 3.4 信号集操作函数
      • 3.4.1 sigprocmask
      • 3.4.2 sigpending
  • 4. 捕捉信号
    • 4.1 内核如何实现信号的捕捉
    • 4.2 sigaction
  • 5. 可重入函数
  • 6. volatile


1. 信号入门


1.1 信号基本概念

Linux中的信号(Signal)是操作系统用来通知进程发生某些事件的机制,可以简单理解为一种“通知”机制。就像你收到一个快递通知一样,信号通知进程某些事件的发生,让进程做出相应的处理。 不属于传递数据,而是属于传递事件。

在Linux中,信号是一种异步的事件通知,通常用于进程之间的通信或系统发生某种异常时的响应。每个信号都有一个编号和一个名称,如 SIGINT(中断信号,通常由Ctrl+C产生)或 SIGKILL(强制终止信号,无法被捕捉或忽略)。

信号有两类:

软件信号(Software Signals):由软件触发,通常用于进程间通信或通知某些操作,如 SIGUSR1 和 SIGUSR2。

硬件信号(Hardware Signals):由硬件事件触发,通常与操作系统内核的异常情况相关,比如 SIGSEGV(段错误)和 SIGFPE(浮点异常)。

信号的主要特性:

异步性:信号是异步的,即它们不需要进程主动检查,而是操作系统会在合适的时机将信号送达给进程。

进程间通信:信号通常用来在不同进程之间传递信息,告知进程某个事件发生了,例如进程结束或收到用户中断。

信号处理方式:进程在接收到信号时,可以选择默认处理方式、忽略信号,或者捕捉信号并执行自定义的信号处理程序。

信号的处理机制:

当进程收到信号时,可以采取不同的方式处理信号:

1、默认处理:每个信号都有默认的处理方式,如 SIGINT 通常是终止进程。

2、捕捉信号:通过编写信号处理程序,进程可以在收到信号时执行特定的操作。例如,程序可以捕捉 SIGTERM 信号来执行清理工作再退出。

3、忽略信号:进程可以选择忽略某些信号,如忽略 SIGPIPE 信号(用于管道破裂时),这样进程不会因为管道错误而终止。

信号的传递:

信号的传递是由内核通过操作系统的调度机制完成的。当某个信号产生时,内核会将信号送给目标进程,并在下次进程调度时通知该进程。

总结起来,Linux信号就是用来异步通知(指通知的发送和接收不在同一时间发生。换句话说,发送通知的操作和接收通知的操作是独立的,接收方不需要等通知发送完毕再继续其他任务,通知本身的处理是“非阻塞”的)进程某些事件发生的机制。进程可以选择如何响应这些信号,比如通过捕捉信号执行自定义操作,或者直接忽略信号。

同步通知:在同步模式下,发送通知的操作和接收通知的操作是紧密绑定的,接收方必须等通知被发送完并处理完之后,才能继续做其他工作。比如一个函数调用,在调用过程中,程序会暂停执行,直到函数返回结果,才能继续后续操作。

当信号产生的时候,我们不一定需要立马去处理信号,因为也可能在做优先级更高的事情。(只是信号已经到来,暂时没有处理——在合适的时候进行处理;信号到来后,此时这个信号已经产生,但是暂时没有处理,此时引入时间窗口 -> 用某种方式记录这个信号已经产生)

总结:

1、进程虽然现在没有收到信号,但进程知道收到信号之后,该怎么做。进程内部一定可以识别“信号”,程序员设计进程的时候,已经内置了处理方案,信号属于进程内部特有的特征。

2、当信号到来后,进程可能正在处理更重要的事情,信号可能不会被立即出来,会等合适的时候在进行处理(处理信号之前,会暂时被进程保存起来)

3、进程开始处理信号的3种模式:默认行为(终止进程、暂停、继续运行等)、自定义行为、忽略信号。

信号是如何发送的以及如何记录的?
信号的记录是在进程的task_struct (PCB) 是结构体变量。进程记录信号其实本质上是为了记录信号“是否”产生。

应该用什么数据结构保存信号数据?——位图

unsigned int signal;0000 0000 0000 0000 0000 0000 0000 0000比特位的位置对应 -> 信号编号
比特位的内容对应 -> 是否收到信号(0没有收到,1表示收到)0000 0000 0000 0000 0000 0000 0100 0000
从倒数第二个bit开始记录:收到6号信号(位于倒数第几个)
进程收到信号后,本质是进程内的信号位图被修改了。
谁有资格修改进程内的数据?————OS
OS是进程的管理者,有绝对的资格能够修改进程数据。
本质上就是OS直接去修改目标进程task_struct中的信号位图。
只有OS有资格发送信号。
但是信号发送的方式可以有多种。
kill -l # Linux中查看信号列表,共62个信号(没有32、33)

在这里插入图片描述

在这里插入图片描述
普通信号的编号范围是[1,31]。


1.2 技术应用角度的信号

$ cat sig.c#include <stdio.h>
int main()
{while(1){printf("I am a process, I am waiting signal!\n");sleep(1);}
}$ ./sigI am a process, I am waiting signal!
I am a process, I am waiting signal!
I am a process, I am waiting signal!
^C

ctrl + c :终止进程 —— 2号信号

signal:这是一个系统调用或函数,用于将特定的信号与一个信号处理函数进行关联,指定当该信号到达时,操作系统应该调用哪个函数进行处理。
在这里插入图片描述
signum:信号编号
handler:回调函数

kill是一个常用的命令,kill用于向进程发送信号

#include <stdio.h>
#include <signal.h>
#include <unistd.h>void handler(int signum) {printf("Received signal %d: SIGINT (Ctrl+C) was pressed!\n", signum);
}int main() {// 设置信号处理函数,捕捉 SIGINT (Ctrl+C)signal(2, handler);while(1) {printf("Running... Press Ctrl+C to send SIGINT.\n");sleep(1);  // 稍作休息,模拟程序运行}return 0;
}/* 
signal() 函数允许你指定自定义的信号处理函数,捕捉并处理特定信号。可以用来修改进程对某些信号的默认响应行为。
handler:这是信号处理函数的名称。handler 是一个函数,它定义了当接收到 SIGINT 信号时应该执行的操作。signal(2, handler):这行代码将 SIGINT 信号(编号为 2)与 handler 函数关联起来。
也就是说,每当进程收到 SIGINT 信号时,内核会调用 handler() 函数来处理它。handler():这是自定义的信号处理函数。当你按下 Ctrl+C 发送 SIGINT 信号时,程序不会直接终止,而是执行 handler 函数。
输出“Received signal 2: SIGINT (Ctrl+C) was pressed!”。
*/
$ ./myproc & 在当前目录下执行 myproc 程序,并且将其作为后台进程运行。
执行该命令后,你的终端不会被 myproc 占用,你可以继续在终端中执行其他命令。背景进程与前台进程:
前台进程:没有使用 &,程序会作为前台进程运行,终端会被程序占用,直到该程序结束,你才能继续输入其他命令。后台进程:加上 & 后,程序变成后台进程,终端可以立即返回提示符,允许你继续执行其他命令。
后台进程会继续在后台运行,直到它完成或被终止。

./myproc & 这条命令的含义是将 myproc 程序作为一个后台进程运行。

1、Ctrl-C 产生的信号只能发给前台进程(后台进程无法被Ctrl+C终止,需要使用kill -3 PID 或kill -SIGQUIT PID或来终止进程)。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。

2、Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像Ctrl-C 这种控制键产生的信号。

3、前台进程在运行过程中用户随时可能按下Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的。

注意:
信号是进程之间事件异步通知的一种方式,属于软中断。

软中断指的是由程序主动触发的中断,它并非由硬件事件(如外部设备发出的信号)直接引起,而是由操作系统或应用程序通过特定机制主动引发的中断。与硬中断不同,软中断通常是在软件层面上处理的,目的是执行某些操作或响应事件。

为什么是“软中断”?异步性:
信号可以在进程执行的任何时刻送达
并且不需要等待进程主动检查或响应(即它是异步的)。
这就像硬件中断一样,突然打断了进程的执行
但与硬件中断不同的是,它是由操作系统内核生成和管理的。非同步执行:
在接收到信号后,进程可以选择如何处理它
可能会执行默认操作(如终止进程、忽略信号)
也可以使用自定义的信号处理函数。
信号的处理并不一定立即发生,而是由操作系统调度。
因此,它与硬中断的直接、快速响应有区别。程序控制:
与硬中断相比,软中断通常可以被程序或操作系统更精确地控制。
例如,操作系统可以设定哪些信号应该被忽略
哪些信号应该被捕捉并由程序处理,这使得信号机制比硬中断更灵活。
硬中断是由硬件设备引发的一种中断机制
用于通知 CPU 或操作系统某个硬件设备需要处理某个事件或数据。
硬中断通常是不可预测和紧急的,硬件设备通过硬中断向 CPU 发出信号
要求 CPU 停止当前的任务并转去处理硬件事件。

信号处理常见方式概览,可选的处理动作有以下三种:

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

为什么要有信号?——为了让进程具有处理突发事件的能力
例如:

系统“出错了”时的报警
有时候程序出错,比如访问了不该访问的内存位置。操作系统会发送信号告诉程序:“出错啦!你访问了不该访问的地方!”这时程序可以根据这个信号做一些处理,比如报告错误或直接退出。

进程之间的“通知”
信号就像是操作系统给进程发的“提醒”或者“通知”。比如,当你在玩游戏时,有个新消息提醒或者有人打电话给你,信号就像这种提醒,让程序知道该做些什么。

告诉程序发生了什么事
假设你正在做一个重要的任务,比如看视频。突然间,如果有个事件发生了,比如你按了 Ctrl+C(想停止当前程序),操作系统就会用信号通知你:“嘿,你的程序被要求终止了!”程序收到信号后可以选择停止,也可以做点其他事(比如保存工作进度后再退出)。


2. 信号的产生


2.1 通过终端按键(如键盘)产生信号

CTRL + \ :3号信号
查看系统资源的命令:
ulimit -a

在这里插入图片描述

图中此时核心转储文件大小为0,若打开文件大小后:

$ ulimit -c 10240$ ulimit -a此时第一行显示为:
core file size    (block, -c) 10240
$ ./myproc hello world
hello world
hello world
hello world
^\Quit (core dumped) # 按Ctrl+\后$ ls
core.23900 # 多了一个临时文件;23900是发生核心转储的进程ID

代码运行中的时候若出错了,我们也需要有方法去判定是由什么原因出错的。
核心转储功能:把进程在内存中的核心数据,转储到磁盘上,一般命名为core.pid 核心转储文件——目的为了调试,定位问题。

核心转储(Core Dump)文件是程序崩溃时的内存快照,它记录了进程在崩溃瞬间的状态,包括 CPU 寄存器、内存数据、调用栈、代码段等信息。核心转储文件的主要作用是调试程序崩溃的原因。

一般云服务器(属于线上生成环境),默认是关闭核心存储功能。
为什么默认要关闭核心存储功能?
1、安全性考虑
核心转储文件可能包含敏感数据,如果核心转储文件被恶意用户访问,可能会导致严重的安全风险。所以,云服务器提供商通常默认禁用 core dump,以降低信息泄露的风险。
2、影响服务器性能当一个大进程崩溃并生成核心转储时,CPU 可能会被 core dump 操作占用,导致其他应用运行变慢。
3、多租户环境,避免影响其他用户。云服务器通常是多租户环境(多个用户共享同一台物理服务器),如果某个用户的进程崩溃并生成大 core dump 文件,可能会影响到其他用户的磁盘空间。

上述内容解释:

$ ulimit -c 10240  
这个命令用于设置核心转储(core dump)文件的最大大小。即打开核心存储功能。
单位是 block(通常 1 block = 1KB)。-c 选项表示 core dump 文件的大小
10240代表最大10MB的core dump文件。这样,当程序崩溃时,如果核心转储功能开启了
它会生成一个大小不超过 10MB 的 core dump 文件。
$ ulimit -a这个命令用于查看当前 shell 进程的所有资源限制,包括:
core file size(核心转储文件大小)
file size(最大文件大小)
max user processes(最大用户进程数)

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

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

相关文章

要素的选择与转出

1.要素选择的三种方式 当要在已有的数据中选择部分要素时&#xff0c;ArcMap提供了三种方式:按属性选择、位置选择及按图形选择。 1)按属性选择 通过设置 SQL查询表达式&#xff0c;用来选择与选择条件匹配的要素。 (1)单击主菜单下【选择】【按属性选择】&#xff0c;打开【按…

Springboot + Vue + WebSocket + Notification实现消息推送功能

实现功能 基于Springboot与Vue架构&#xff0c;首先使用Websocket实现频道订阅&#xff0c;在实现点对点与群发功能后&#xff0c;在前端调用windows自带的消息通知&#xff0c;实现推送功能。 开发环境 Springboot 2.6.7vue 2.6.11socket-client 1.0.0 准备工作 在 Vue.js…

云手机如何防止设备指纹被篡改

云手机如何防止设备指纹被篡改 云手机作为虚拟化设备&#xff0c;其设备指纹的防篡改能力直接关系到账户安全、反欺诈和隐私保护。以下以亚矩阵云手机为例&#xff0c;讲解云手机防止设备指纹被篡改的核心技术及实现方式&#xff1a; 系统层加固&#xff1a;硬件级安全防护 1…

有人DTU使用MQTT协议控制Modbus协议的下位机-含数据库

本文为备忘录&#xff0c;不做太多解释。 DTU型号&#xff1a;G780 服务器&#xff1a;win2018 一。DTU设置 正确设置波特率&#xff0c;进入配置状态&#xff0c;获取当前参数&#xff0c;修改参数&#xff0c;设置并保存所有参数。 1.通道1设置 2.Modbus轮询设置 二&am…

湖北师范大学计信学院研究生课程《工程伦理》9.6章节练习

以下是图片中识别出的文字内容: 1【单选题】当工程师发现所在的企业或公司进行的工程活动会对环境、社会和公众的人身安全产生危害时,应该及时地给予反映或揭发。这属于工程师的( ) A、职业伦理责任 B、社会伦理责任 C、个人伦理责任 D、法律责任 2【单选题】下列哪个不属于工…

Axure RP 9 详细图文安装流程(附安装包)教程包含下载、安装、汉化、授权

文章目录 前言一、Axure RP 9介绍二、Axure RP 9 安装流程1. Axure RP 9 下载2. 启动安装程序3. 安装向导操作4.完成安装 三、Axure RP 9 汉化四、Axure RP 9授权 前言 本基础安装流程教程&#xff0c;将以清晰、详尽且易于遵循的步骤介绍Axure RP 9 详细图文安装流程&#xf…

SpringBoot全局exception处理最佳实践

目录 自定义异常类 抛出异常 全局异常处理器 自定义异常类 通常会继承 Exception 或其子类(如 RuntimeException)来定义业务异常类,用于封装业务相关的错误信息。一般选择继承 RuntimeException,因为它是一个非受检异常,在方法中抛出时不需要显式声明。 // 自定义业…

node ---- 解决错误【Error: error:0308010C:digital envelope routines::unsupported】

1. 报错 在 Node.js 18.18.0 的版本中&#xff0c;遇到以下错误&#xff1a; this[kHandle] new _Hash(algorithm, xofLen);^ Error: error:0308010C:digital envelope routines::unsupported这个错误通常发生在运行项目或构建时&#xff0c;尤其是在使用 Webpack、Vite 或其他…

浙江大学郑小林教授解读智能金融与AI的未来|附PPT下载方法

导 读INTRODUCTION 随着人工智能技术的飞速发展&#xff0c;智能金融已成为金融行业的重要变革力量。浙江大学人工智能研究所的郑小林教授在2025年3月24日的《智能金融&#xff1a;AI驱动的金融变革》讲座中&#xff0c;深入探讨了新一代人工智能在金融领域的应用及未来展望。 …

如何实现浏览器中的报表打印

在浏览器中实现打印一个报表&#xff0c;可以通过以下几种方法来完成。这里介绍一个基本的流程和相关代码示例&#xff1a; 1. 使用 JavaScript 的 window.print() 方法 这是最简单的方法&#xff0c;它会打开打印对话框&#xff0c;让用户选择打印选项。 示例代码&#xff1…

Linux系统调用编程

进程和线程 进程是操作系统资源分配的基本单位&#xff0c;拥有独立的地址空间、内存、文件描述符等资源&#xff0c;进程间相互隔离。每个进程由程序代码、数据段和进程控制块&#xff08;PCB&#xff09;组成&#xff0c;PCB记录了进程状态、资源分配等信息。 线程是…

【力扣hot100题】(054)全排列

挺经典的回溯题的。 class Solution { public:vector<vector<int>> result;void recursion(vector<int>& nums,vector<int>& now){if(nums.size()0){result.push_back(now);return ;}for(int i0;i<nums.size();i){now.push_back(nums[i]);…

【Ragflow】11. 文件解析流程分析/批量解析实现

概述 本文继续对ragflow文档解析部分进行分析&#xff0c;并通过脚本的方式实现对文件的批量上传解析。 文件解析流程 文件解析的请求处理流程大致如下&#xff1a; 1.前端上传文件&#xff0c;通过v1/document/run接口&#xff0c;发起文件解析请求 2.后端api\apps\docum…

2024年零知识证明(ZK)研究进展

Sumcheck 整个领域正在转向更多地依赖于 Sumcheck Protocol Sumcheck是用于验证多项式承诺的协议,常用于零知识证明(ZKP)中,尤其是在可验证计算和扩展性上。它的主要目的是通过对多项式进行分段检查,从而保证某个多项式在给定输入上的正确性,而不需要直接计算出整个多项…

thinkphp每条一级栏目中可自定义添加多条二级栏目,每条二级栏目包含多个字段信息

小程序客户端需要展示团购详情这种结构的内容,后台会新增多条套餐,每条套餐可以新增多条菜品信息,每条菜品信息包含菜品名称,价格,份数等字段信息,类似于购物网的商品多规格属性,数据表中以json类型存储,手写了一个后台添加和编辑的demo 添加页面 编辑页面(json数据…

Vue3引入ElementPlus

1.ElementPlus属于第三方的应用框架&#xff0c;官网地址&#xff1a;设计 | Element Plus &#xff0c;学习可以参考该网站的指南。 2.安装element-plus &#xff0c;指令为&#xff1a;npm install element-plus --save 3.引入elementplus的全局&#xff0c;组件、样式、图标…

react+antd封装一个可回车自定义option的select并且与某些内容相互禁用

需求背景 一个select框 现在要求可多选 并且原有一个any的选项 其他选项为输入后回车自己增加 若选择了any 则其他选项不可选择反之选择其他选项any不可选择 并且回车新增时也不可直接加入到选中数组只加入到option内 并且不可重复添加新内容 实现过程 <Form.Item …

Oracle数据库数据编程SQL<8 文本编辑器Notepad++和UltraEdit(UE)对比>

首先&#xff0c;用户界面方面。Notepad是开源的&#xff0c;界面看起来比较简洁&#xff0c;可能更适合喜欢轻量级工具的用户。而UltraEdit作为商业软件&#xff0c;界面可能更现代化&#xff0c;功能布局更复杂一些。不过&#xff0c;UltraEdit支持更多的主题和自定义选项&am…

【学Rust写CAD】30 Alpha256结构体补充方法(alpha256.rs)

源码 impl Alpha256 {#[inline]pub fn alpha_mul(&self, x: u32) -> u32 {let mask 0xFF00FF;let src_rb ((x & mask) * self.0) >> 8;let src_ag ((x >> 8) & mask) * self.0;(src_rb & mask) | (src_ag & !mask)} }代码分析 功能 输…

Linux systemd 服务全面详解

一、systemd 是什么&#xff1f; systemd 是 Linux 系统的现代初始化系统&#xff08;init&#xff09;和服务管理器&#xff0c;替代传统的 SysVinit 和 Upstart。它不仅是系统启动的“总指挥”&#xff0c;还统一管理服务、日志、设备挂载、定时任务等。 核心作用 服务管理…