Linux进程信号(信号的产生)
目录
什么是信号?
信号的产生
信号产生方式1:键盘
前台进程
后台进程
查看信号
signal系统调用
案例
理解进程记录信号
软件层面
硬件层面
信号产生方式2:指令
信号产生方式3:系统调用
kill系统调用
案例
其他产生信号的函数调用
1.raise
2.abort
信号产生方式4:软件条件
什么是软件条件?
alarm系统调用
使用
1.
2.
3.
信号的产生5:异常
示例1:
示例2:
那么os如何知道进程内部错误?
理解一下野指针的异常
Term和Core的区别
什么是信号?
信号!=信号量
信号:是一种用户,OS,其他进程,向目标进程发送异步事件的一种方式。
同步和异步:
1.怎么识别信号?
识别信号是内置的。即进程识别信号时程序的内置属性。可以类比一下语言的内置数据类型(int,double)
2.信号产生后,进程知道怎么处理吗?知道 。如果没产生,进程知道怎么处理吗?也知道,因为信号的处理方法在产生之前就已经准备好了。
3.信号会被进程立即处理吗?
不一定,如果不,那么什么时候处理呢?进程会在一个合适的时候处理。
信号到来 --> <进程不立即处理,记录信号> --> 合适的时候处理信号
4.处理信号的方法: 1.默认行为 2.忽略信号3.自定义动作
信号的产生
信号产生方式1:键盘
这有一段死循环的程序
#include <iostream>
#include <unistd.h>
int main()
{while (true){std::cout << "hello world" << std::endl;sleep(1);}return 0;
}
从键盘中输入 ctrl+c 可以前台进程杀掉前台进程。
前台进程
命令 : ./程序名
运行起来的是前台进程也可以用ctrl+c杀掉进程
后台进程
命令 : ./进程名&
后台进程无法用 ctrl+c 杀死
杀掉后台进程的方法:1. fg命令将后台进程切换到前台,在ctrl+c杀掉进程。
2. kill -9 pid(对应进程的pid)
方法一:
方法二:
查看信号
kill -l
man 7 signal//中可以找到相应信号的描述
signal系统调用
信号的自定义捕捉
signal的作用是捕捉signum号信号,捕捉之后,执行handler指向的函数
signum: 要捕捉的信号
#define SIGQUIT 3
handler:处理函数
案例
ctrl+\ 默认终止进程
#include <iostream>
#include <unistd.h>
#include <signal.h>
void handler(int signo)
{std::cout << "signo: " << signo << std::endl;
}
int main()
{//捕捉 3)SIGQUIT信号signal(SIGQUIT, handler);while (true){std::cout << "hello world" << std::endl;sleep(1);}return 0;
}
ctrl+\,被捕捉不再执行默认行为(默认终止),而是将这个信号传给signo并调用自定义函数
根据上面的案例是不是我们捕捉所有信号,那么这个死循环程序就不会被杀死了呢?
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
using func_t = std::function<void(int)>;
void handler(int signo)
{std::cout << "signo: " << signo << std::endl;
}
int main()
{//signal(SIGQUIT, handler);//捕捉信号for(int i = 1;i<=31;i++){func_t f = signal(i,handler);std::cout<<"捕捉:"<<i<<std::endl;}while (true){std::cout << "hello world" << std::endl;sleep(1);}return 0;
}
从结果上可以知道ctrl+c ctrl+\因为被捕捉了,所以杀不掉进程,但kill -9 可以 杀掉进程,也就说明了,9)SIGKILL 不能被捕捉。
理解进程记录信号
软件层面
键盘(比如ctrl+c) -> os -> 进程 --> 记录信号
因为os管理外设,所以键盘将信号传给os,os也管理进程,os在将信号传给进程,之后进程记录信号。
进程如何记录信号?
总结:
发送流程:键盘中的信号发送给os,os在发送给进程,修改进程对应的信号位图和其维护处理方法的函数指针数组。
无论什么信号都是由os发送的。
os是task_struct的唯一管理者,所以只有 os有权利修改信号位图。
硬件层面
os是如何知道键盘上有数据?
轮徇(不可以,os的任务太多了)
硬件中断
冯诺依曼体系结构
在数据层面上,我们知道cpu不与外设直接打交道。而是通过存储器
但在cpu和键盘是连接的,键盘可以直接将数据交给cpu
硬件中断 --> cpu告诉os,键盘上有数据 --> 这样硬件和os就可以并行执行了
信号vs信号中断
信号是纯软甲的
信号中断是纯硬件的
信号产生方式2:指令
指令:
kill -信号 相应进程的pid
信号产生方式3:系统调用
kill系统调用
kill的作用:就是OS向(pid)进程 发送sig信号
使用代码:
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>
int main()
{int cnt= 5;while(true){std::cout<<cnt<<std::endl;if(cnt<=0)kill(getpid(),SIGQUIT);sleep(1);cnt--;}return 0;
}
执行结果:
kill()系统调用与kill命令的关系
kill命令行就是封装的kill()系统调用。
案例
简单实现下自己的kill
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>void Usage(char* argv)
{std::cout<<"Usage error: "<<argv<<" signo"<<" pid"<<std::endl;exit(1);
}
//./kill 9 pidint main(int argc,char* argv[])
{if(argc!=3){//正确使用提醒Usage(argv[0]);}int signo = std::stoi(argv[1]);pid_t pid = std::stoi(argv[2]);int ret = kill(pid,signo);if(ret<0){perror("kill");exit(2);}return 0;}
执行结果:
其他产生信号的函数调用
1.raise
作用:让OS向调用该函数的进程返送sig信号
2.abort
作用:让OS向调用该函数的进程返送6号信号(该进程被干掉)
这两个函数比较简单
这两个函数都是由kill封装的,libc库函数
kill(getpid(),sig);//raise
kill(getpid(),6);//abort
信号产生方式4:软件条件
什么是软件条件?
由软件条件产生信号,通常指的是在软件应用程序中,根据某些特定的条件或逻辑判断来触发或生成信号
比如:管道中,读端关闭,但写端没有关闭 这时,os回想进程发送 13)SIGPIPE信号
alarm系统调用
作用:设置一个seconds秒的闹钟,时间一到就会给调用闹钟的进程发送 14)SIGALRM信号
alarm(条件);
里面设置的时间就相当于条件,满足条件就发送信号。
OS中维护的定时器的大概内核数据结构
使用
1.
#include <iostream>
#include <unistd.h>int main()
{alarm(1);int cnt = 0;while(true){//一秒打印多少次std::cout<<cnt<<std::endl;cnt++;}return 0;
}
结果:
打印了11万多次,快只能说很慢。
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>int cnt = 0;
void handler(int signo)
{std::cout<<cnt<<std::endl;exit(0);
}
int main()
{alarm(1);signal(SIGALRM,handler);while(true){//std::cout<<cnt<<std::endl;cnt++;}return 0;
}
结果:计算了将近16亿次
从上面两个程序可以看出,IO影响计算速度。
2.
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>int main()
{alarm(5);sleep(1);int n = alarm(0);//alarm(0)取消闹钟 n上一个闹钟剩余的时间std::cout<<n<<std::endl;return 0;
}
3.
pause
作用:等待信号
闹钟是一次性的发送完信号后就被取消。
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>
#include <vector>
using func_t = std::function<void()>;int cnt = 0;
std::vector<func_t> v;//任务void handler(int signo)
{for (auto &e : v){e();}alarm(2);cnt++;
}
int main()
{v.push_back([](){ std::cout << "我是一个日志任务" << std::endl; });v.push_back([](){ std::cout << "我是一个下载任务" << std::endl; });v.push_back([](){ std::cout << "我是一个mysql任务" << std::endl; });alarm(2);//一次性闹钟,超时后就会被取消signal(SIGALRM, handler);while (true){pause();//等待信号std::cout << "我醒来了..." << std::endl;std::cout << "cnt: " << cnt << std::endl;}
}
运行结果:
将上述逻辑中的信号变为硬件中断,就是OS的运行逻辑。
OS本质上就是一个中断处理程序
信号的产生5:异常
示例1:
野指针
int main()
{int *p = nullptr;*p = 0;//野指针return 0;
}
Segmentation fault 段错误
11)SIGEGV
示例2:
int main()
{int a = 10;a/=0;return 0;
}
Floating point exception 浮点异常
8)SIGFPE
现在我们可以理解一下为什么程序会崩溃?
出现错误时,OS会向进程发送相应的信号,从而进程被干掉。
那么os如何知道进程内部错误?
比如:div 0
cpu中有状态寄存器 Eflag,Eflag中有个core dump(溢出标记为)标记为,1.cpu计算错误
0.无错误
验证:
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>
#include <wait.h>int main()
{pid_t pid = fork();if(pid==0){//子进程int a = 10;a/=0;}else{int status;waitpid(pid,&status,0);std::cout<<"core dump: "<<((status>>7)&1)<<std::endl;std::cout<<"signo: "<<(status&0x7F)<<std::endl;}
}
结果:
正如所料:core dump被设为1,并向子进程发送8)SIGFPE信号
--------------------------------------------------------------------------------------------------------------------------------
void handler(int signo)
{std::cout<<"signo: "<<signo<<std::endl;
}
int main()
{pid_t pid = fork();if(pid==0){//子进程int a = 10;a/=0;}else{int status;waitpid(pid,&status,0);std::cout<<"core dump: "<<((status>>7)&1)<<std::endl;std::cout<<"signo: "<<(status&0x7F)<<std::endl;}
}
差不多的程序如果捕获了8号信号,
结果:
os一直发送8号信号。
总结:
cpu错误 --> 谁弄坏了cpu,os发送信号杀死进程 (--> 如果捕捉了8号信号--->进程没退出--->还要调度-->还要切换执行等 --> os不会修复Eflag中core dump(1)-->一直触发信号)
理解一下野指针的异常
野指针的错误是由cpu中MMU错误引起的
Term和Core的区别
Trem:正常终止,不需要debug
Core:核心转储--->在当前目录下形成core文件-->进程崩溃,将进程在内存中的部分信息保存起来,方便以后调试-->一般被云服务器关闭(如果崩溃一次形成一个新的core,那么就可能把磁盘空间占满)
但当前目录下没有啊
如何打开?
ulimit -a//查看
可以看到core file size为0;
ulimit -c 大小//改变core file size
readelf -S ./sig //查看程序elf格式
运行程序就可已生成core.pid的文件
如果无法生成core文件的话
在root下,输入下面的命令就可以了
echo core > /proc/sys/kernel/core_pattern
core-file core.pid//方便调试
如果是子进程异常呢?core的生成条件?
core dump--> 退出信号的终止动作是core && 云服务器开启core
相关文章:

Linux进程信号(信号的产生)
目录 什么是信号? 信号的产生 信号产生方式1:键盘 前台进程 后台进程 查看信号 signal系统调用 案例 理解进程记录信号 软件层面 硬件层面 信号产生方式2:指令 信号产生方式3:系统调用 kill系统调用 案例 其他产生信号的函数调用 1.rais…...

97_api_intro_imagerecognition_pdf2word
通用 PDF OCR 到 Word API 数据接口 文件处理,OCR,PDF 高可用图像识别引擎,基于机器学习,超精准识别率。 1. 产品功能 通用识别接口;支持中英文等多语言字符混合识别;formdata 格式 PDF 文件流传参…...

【算法】【优选算法】二分查找算法(上)
目录 一、二分查找简介1.1 朴素二分模板1.2 查找区间左端点模版1.3 查找区间右端点模版 二、leetcode 704.⼆分查找2.1 二分查找2.2 暴力枚举 三、Leetcode 34.在排序数组中查找元素的第⼀个和最后⼀个位置3.1 二分查找3.2 暴力枚举 四、35.搜索插⼊位置4.1 二分查找4.2 暴力枚…...

springboot初体验
目录 环境 controller 修改端口号 更改banner图标 运行结果 最核心的:自动装配 环境 jdk17springboot3.3.5maven3.8.2 controller controller层和启动类同级 package com.example.demo.controller; import org.springframework.web.bind.annotation.RequestMapping;…...

使用kalibr_calibration标定相机(realsense)和imu(h7min)
vslam-evaluation/VINS/Installation documentation/4.IMU和相机联合标定kalibr_calibration.md at master DroidAITech/vslam-evaluation GitHub 目录 1.kalibr安装 1.1安装依赖项 1.2创建工作空间 1.3下载kalibr并编译 1.4设置环境变量 2.准备标定板 3.配置驱动和打…...
绿色工厂认定流程
以下是认定绿色工厂的一般流程: 编制年度创建计划 各省辖市、省直管县(市)会结合本地区重点产业发展现状,挑选一批基础条件良好、有创建意愿和条件的企业进行储备培育,并依据当地工业企业发展实际情况按年度制定绿色工…...

《Python游戏编程入门》注-第5章5
《Python游戏编程入门》的“Analog Clock示例程序”部分讲解了模拟时钟的实现方法。该模拟时钟可以通过时针、分针和秒针的旋转,显示当前时间,如图1所示。 图1 模拟时钟 1 绘制圆 从图1中可以看出,时钟的边缘是一个白色的圆,可以通过如图2所示的代码进行绘制。 图2 绘制圆…...

LangChain Ollama实战文献检索助手(二)少样本提示FewShotPromptTemplate示例选择器
本期是用样例来提示大模型生成我们想要的答案。即在输入中给定提示的样例,以及提示模板,然后匹配较相关的样例进行文献综述。 创建示例样本FewShotPromptTemplate 这里我用GTP-o1生成了几个回答,作为样本 samples [{"theme": &…...
K倍区间 C++
1230. K倍区间 - AcWing题库 一开始想到的用前缀和来做,时间复杂度为O(n^2),Time Limit Exceeded #include <iostream> #include <cstring> #include <algorithm> #include <cstdio>using namespace std;const int N 100010;int n,k; in…...

Linux - 弯路系列3:安装和编译libvirt-4.5.0
系统:Anolis8(离线) 目录 1、步骤2、make过程中的错误错误1:error: xdr_u_int64_t undeclared (first use in this function) 3、make install的错误错误1:/usr/bin/mkdir -p ""/usr/local/etc/libvirt/nwf…...

Jenkins插件使用问题总结
Git Push插件 插件介绍 主要是用于git推送代码到远程仓库中使用,插件地址 pipeline中使用 官方说明中只有一句代码gitPush(gitScm: scm, targetBranch: env.BRANCH_NAME, targetRepo: origin) 流水线语法中也做的不齐全所以一开始我老是设置错,导致代…...

u盘怎么重装电脑系统_u盘重装电脑系统步骤和详细教程【新手宝典】
u盘怎么重装电脑系统?一个u盘怎么重装电脑系统呢,需要将u盘制作成u盘启动盘pe,然后通过U盘启动盘进入pe进行安装系统,下面小编就教大家u盘重装电脑系统步骤和详细教程。 u盘启动是什么意思? U盘启动盘是一种具有特殊功…...
Sql server查询数据库表的数量
SELECT count(*) FROM sys.objects WHERE typeU --统计表数量 SELECT NAME FROM sys.objects WHERE typeU --列出表名称 或者 SELECT COUNT(*) FROM SysObjects Where XTypeU --统计表数量 SELECT Name FROM SysObjects Where XTypeU --列出表名称 --判断字…...

Linux学习笔记之软件包管理RPM与YUM
RPM包的管理 介绍 RPM(RedHat Package Manager)用于互联网下载包的打包及安装工具,它包含在某些Linux分发版中。他生成具有.RPM扩展名的文件。RPM类似Windows的setup.exe,这一文件格式虽然打上了RedHat的标志,但理念…...
15分钟学 Go 第 41 天:中间件的使用
第41天:中间件的使用 目标:学习如何在Go语言的Web服务中使用中间件 中间件(Middleware)是Web开发中的一种常见设计模式,通常用于处理请求和响应过程中的一些共通功能。比如:日志记录、认证授权、请求处理…...
《Python 与 SQLite:强大的数据库组合》
《Python 与 SQLite:强大的数据库组合》 一、Python 与 SQLite 的结合二、安装与连接(一)安装 SQLite 模块(二)连接到数据库 三、数据库操作(一)创建表格(二)插入数据&am…...

Golang | Leetcode Golang题解之第552题学生出勤记录II
题目: 题解: const mod int 1e9 7type matrix [6][6]intfunc (a matrix) mul(b matrix) matrix {c : matrix{}for i, row : range a {for j : range b[0] {for k, v : range row {c[i][j] (c[i][j] v*b[k][j]) % mod}}}return c }func (a matrix) p…...

Vue3 常用代码指南手抄,超详细 cheatsheet
一、Vue3 基础 1.1 创建 Vue3 项目 使用 Vite 创建 npm create vitelatest my-vue-app -- --template vue cd my-vue-app npm install npm run dev使用 Vue CLI 创建 npm install -g vue/cli vue create my-vue-app1.2 项目结构 my-vue-app ├── node_modules ├── pu…...
结构体是否包含特定类型的成员变量
结构体是否包含特定类型的成员变量 在C中,可以使用模板元编程和类型特性(type traits)来判断一个结构体是否包含特定类型的成员变量。这通常通过std::is_member_object_pointer类型特性来实现,它可以用来检查给定的成员指针是否指…...

堆排序与链式二叉树:数据结构与排序算法的双重探索
大家好,我是小卡皮巴拉 文章目录 目录 引言 一.堆排序 1.1 版本一 核心概念 堆排序过程 1.2 版本二 堆排序函数 HeapSort 向下调整算法 AdjustDown 向上调整算法 AdjustUp 二.链式二叉树 2.1 前中后序遍历 链式二叉树的结构 创建链式二叉树 前序遍历…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【笔记】结合 Conda任意创建和配置不同 Python 版本的双轨隔离的 Poetry 虚拟环境
如何结合 Conda 任意创建和配置不同 Python 版本的双轨隔离的Poetry 虚拟环境? 在 Python 开发中,为不同项目配置独立且适配的虚拟环境至关重要。结合 Conda 和 Poetry 工具,能高效创建不同 Python 版本的 Poetry 虚拟环境,接下来…...
生成对抗网络(GAN)损失函数解读
GAN损失函数的形式: 以下是对每个部分的解读: 1. , :这个部分表示生成器(Generator)G的目标是最小化损失函数。 :判别器(Discriminator)D的目标是最大化损失函数。 GAN的训…...

华为云Flexus+DeepSeek征文 | MaaS平台避坑指南:DeepSeek商用服务开通与成本控制
作者简介 我是摘星,一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型,将实际使用经验分享给大家,希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 作者简介 前言 一、技术架构概览 1.1 整体架构设…...

2025-06-01-Hive 技术及应用介绍
Hive 技术及应用介绍 参考资料 Hive 技术原理Hive 架构及应用介绍Hive - 小海哥哥 de - 博客园https://cwiki.apache.org/confluence/display/Hive/Home(官方文档) Apache Hive 是基于 Hadoop 构建的数据仓库工具,它为海量结构化数据提供类 SQL 的查询能力…...