Linux(十二)信号

        今天我们就要来一起学习信号啦!!!还记得小编在之前的文章中说过的ctrl+c吗?之前小编没有详细介绍过,现在我们就要来学习啦!!!

一、信号的基本介绍

        首先,小编带领大家先一起学习一下什么是信号吧。

        信号是系统响应某个条件而产生的事件,进程接收到信号会执行相应的操作

        大家要注意,我们在使用信号时,是需要添加头文件的。与信号有关的系统调用在<signal.h>头文件中。

1、信号的存储位置

旧版

vim /usr/include/x86_64-linux-gnu/bits/signum.h 

新版(23版)

vim /usr/include/x86_64-linux-gnu/bits/signum-arch.h

vim /usr/include/x86_64-linux-gnu/bits/signum-generic.h

2、常见信号对应的功能

SIGBORT      *进程异常终止

SIGALRM      超时警告

SIGFPE         *浮点运算异常

SIGHUP         连接挂断

SIGILL            *非法指令

SIGINT            终端中断

SIGKILL           终止进程(此信号不能被捕获或忽略)

SIGPIPE          向无读进程的管道写数据

SIGQUIT          终端退出

SIGSEGV         *无效内存段访问

SIGTERM        终止

SIGUSR1         用户定义信号1

SIGUSR2         用户定义信号2

(在这里,重点的信号用了加粗提醒大家一定要记住,在这篇文章里,小编还不会向大家介绍SIGPIPE,在后面小编介绍管道时,会结合前边的内容和新的内容全面介绍管道)

3、信号的值

            信号名称  信号代号

#define SIGHUP 1

#define SIGINT 2     //键盘按下 Ctrl+c 时,会产生终端中断信号

#define SIGQUIT 3  //键盘按下 Ctrl+\时,会产生终端退出信号

#define SIGILL 4

#define SIGTRAP 5

#define SIGABRT 6

#define SIGIOT 6

#define SIGBUS 7

#define SIGFPE 8

#define SIGKILL 9     //该信号的响应方式不允许改变

#define SIGUSR1 10

#define SIGSEGV 11

#define SIGUSR2 12

#define SIGPIPE 13    //读端关闭的描述符,写端写入时产生,该信号会终止程序(向无读进程的管道写数据)

#define SIGALRM 14

#define SIGTERM 15    //系统 kill 命令默认发送的信号

#define SIGSTKFLT 16

#define SIGCHLD 17     //子进程结束后,内核会默认给父进程发送该信号

#define SIGCONT 18

#define SIGSTOP 19

#define SIGSTP 20

#define SIGTTIN 21

#define SIGTTOU 22

#define SIGURG 23

(通过这个,小编是想告诉大家,这些信号其实对应的就是数字)

二、信号的响应方式

信号有三种响应方式:默认、忽略、自定义

1、信号处理函数

        在Linux系统中,我们想要了解一个新的知识必不可少的就是帮助手册啦!!!大家还记得怎么使用吗?

        答案就是:man signal

2、 三种响应方式

(1)默认

        如果signal函数的参数为 SIG_DFL,则系统将使用默认的信号处理动作。

        大家可以输入命令“man 7 signal”查看默认处理方式,当然啦,小编也会为大家展示出来。

        在上图,小编只截取了刚刚加粗的几个信号,想看完整的小伙伴可以自己输入命令“man 7 signal”,往下翻就能看到啦。

(2)忽略

        如果signal函数的参数为 SIG_IGN,则系统将忽略该信号。

(3)自定义

        信号自定义处理,其实是对信号进行捕捉,然后让信号执行自定义的方法。

下面,小编向大家演示一下默认的处理方式(也就是收到信号后,进程按照信号默认的方式去处理)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<signal.h>
int main()
{while(1){printf("main run\n");sleep(1);}   exit(0);
}

在上述代码中,小编写了一个while(1)的循环,会一直执行, 当我们键盘按下ctrl+c时,其实就是因为该进程收到了一个信号:SIGNT——终端中断的信号(2号信号);就是说,在键盘上按下ctrl+c时,会给当前终端前台执行的进程发送SIGINT信号;

3、改变型号的响应方式

(1)将默认改为自定义

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<signal.h>
#include<string.h>
void sig_fun(int sig)
{printf("sig=%d\n",sig);
}
int main()
{signal(SIGINT,sig_fun);//这里不是调用,这里是作约定while(1){printf("main run\n");sleep(1);}   exit(0);
}

 那我们该如何结束进程呢?

方法一(图上方法):我们可以通过ctrl+\这个是终端退出的信号

方法二:打开另外一个终端,通过ps -eflgrep test[test是程序名,可替换]这个命令找到该进程的pid,然后kill掉它。(这也是我们在前面学习kill时掌握的方法)

(2)将默认改为忽略

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<signal.h>
#include<string.h>
int main()
{signal(SIGINT,SIG_IGN);//这里不是调用,这里是作约定while(1){   printf("main run\n");sleep(1);}   exit(0);
}

4、SIGCHLD信号

(1)子进程结束,父进程会收到内核发送的SIGCHLD信号(注意:内核发送)

大家还记得我们在学习fork复制进程中的父子进程时用到的代码吗?

小编把代码放到这里帮助大家回顾昂

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>int main(){char *s=NULL;int n=0;pid_t id=fork();if(pid==-1){printf("fork err\n");exit(1);}if(id == 0){s="child";n=3;}//子进程else{s="parent";n=7;}//父进程int i=0;for(;i<n;i++){printf("s=%s\n",s);sleep(1);}exit(0);
}

在学习僵死进程时,小编说过父进程没有获取退出码是会产生僵死进程的;

在上面这段代码里,其实子进程结束了,已经给父进程发送了一个信号.只不过父进程忽略了;那么,我们修改一下代码,让父进程收到子进程的代码,打印一下收到的信号代号,不要忽略掉;

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>void sig_fun(int sig)
{printf("sig = %d\n",sig);printf("child over!\n");
}
int main()
{int n=0;char *s = NULL;pid_t pid=fork();if(pid == -1) {   printf("fork err\n");exit(1);}   if(pid==0){   n=3;s="child";}   else{   signal(SIGCHLD,sig_fun);//子进程结束,内核会默认给父进程发送信号n=7;s="parent";}for(int i =0;i<n;i++){printf("s=%s\n",s);sleep(1);}exit(0);
}

        由执行结果可以看出,子进程结束,确实是会给父进程发送17号信号SIGCHLD;只不过遇到默认情况,父进程不会理会而已;所以,这个17号信号的默认方式就是忽略;
        再次强调一下,这个不是子进程发送的信号,是内核发送的信号;

大家还记得处理僵死进程的两种方法

(1)父进程先结束(2)父进程调用wait()方法获取子进程的退出码

两个方法的本质是一样的,但是方法二会阻塞,就是父进程在等子进程结束,才会获取退出
码。结合信号,如何处理,让它不再阻塞呢?

父进程调用wait是配合信号使用的。让我们通过下面的代码观察一下吧!

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<wait.h>//注意,wait的头文件不要忘记void sig_fun(int sig)
{printf("sig = %d\n",sig);printf("child over!\n");int val;wait(&val);//我们也可以简单写,就是不获取退出码,只要不变成僵死进程就可以//wait(NULL);
}
int main()
{int n=0;char *s = NULL;pid_t pid=fork();if(pid == -1) {   printf("fork err\n");exit(1);}   if(pid==0){   n=3;s="child";}else{signal(SIGCHLD,sig_fun);//子进程结束,内核会默认给父进程发送信号n=7;s="parent";}for(int i =0;i<n;i++){printf("s=%s\n",s);sleep(1);}exit(0);
}

 

三、信号实例练习

1、收到SIGINT这个信号,第一次打印信号的代号,第二次按照默认形式把进程结束

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<signal.h>
void sig_fun(int sig)
{printf("sig = %d\n",sig);signal(sig,SIG_DFL);
}
int main(){signal(SIGINT,sig_fun);//这里不是调用,这里是作约定while(1){   printf("main run\n");sleep(1);}   exit(0);
}

 

2、自己实现kill命令

(1)系统调用kill与kill命令

kill也是一个命令,它底层就封装了我们的系统调用kill;

所以,man kill是1命令,man 2 kill才是系统调用;

man 2 kill得到原型:

int kill(pid_t pid,int sig);
就是向PID为pid的发送sig信号;
返回值为-1说明失败,0表示成功.

(2)回顾kill命令

        执行kill PID命令,这个就是系统调用,默认发送了15号信号。比如我们sleep 500,然后
打开另外一个终端kill掉它,这个kill就是默认发送了15号信号。

(3)实现kill命令

自己实现kill命令,需要PID,需要信号代号。就是我们也要写一个类似kill-9 PID 的命令;为什么需要信号代号呢?

9号信号是一个特殊的信号,它是不允许改变响应方式的。

比如暂停进程(ctrl+Z),那么kill不掉,就需要9号信号强制结束。

写一个类似kill-9 PID的命令;(./mykill PID SIG)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<signal.h>//./mykill pid 信号代号
int main(int argc,char *argv[])
{if(argc!=3){printf("argc error!\n");return -1; }   int pid  = 0;int sig = 0;sscanf(argv[1],"%d",&pid);sscanf(argv[2],"%d",&sig);if(kill(pid,sig)==-1){   perror("kill error!\n");//perror是打印出错信息,输出错误原因}   exit(0);
}

 

(4)15号信号和9号信号

        运行sleep 500这个进程,发现使用自己的mykill命令发送15号信号显示的是“已终止(Terminated)",发现使用自己的mykill命令发送9号信号是“已杀死(killed)",和系统的kill命令是一样的。

        那可能有小伙伴就会说kill命令没有传递信号代号,其实是一样的,也就是mykill传递两个参数即可,把信号代号也就是argv[2]定义成15,或者9即可。

        在这里小编想补充一下,其实19号信号也不能被忽略,它是暂停进程。

【小编有话说】

        本次内容就要结束啦,截止到这篇文章,小编其实已经带领大家自己写了两个命令了,分别是mycp和mykill,还有小伙伴记得嘛,mycp是在读写操作那里实现的。小编现在正在筹备一个关于LINUX项目的文章,大概可能会再过两篇Linux文章就会发布啦,到时后希望小伙伴们能够多多捧场呀!!!

        最后还是老三样,点赞收藏和关注~

        喜欢小编的文章就不要忘记这三样,点赞收藏加关注,找到小编不迷路~

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

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

相关文章

Dify开发实战-自制插件 和安装python3最新版本 记录版本 后续会持续更新

自定义插件 Dify 插件脚手架工具Python 环境&#xff0c;版本号 ≥ 3.12 安装Python 一 进入官网 https://www.python.org/downloads/windows/ 点击下载 二、安装python&#xff08;本文中有借鉴其他图片 所以图片展示python版本可能不一致 请忽略&#xff09; 1.双击打开py…

Docker安装、配置Redis

1.如果没有docker-compose.yml文件的话&#xff0c;先创建docker-compose.yml 配置文件一般长这个样子 version: 3services:redis:image: redis:latestcontainer_name: redisports:- "6379:6379"command: redis-server --requirepass "123456"restart: a…

Parasoft C++Test软件单元测试_操作指南

系列文章目录 Parasoft C++Test软件静态分析:操作指南(编码规范、质量度量)、常见问题及处理 Parasoft C++Test软件单元测试:操作指南、实例讲解、常见问题及处理 Parasoft C++Test软件集成测试:操作指南、实例讲解、常见问题及处理 进阶扩展:自动生成静态分析文档、自动…

二级索引详解

二级索引详解 二级索引(Secondary Index)是数据库系统中除主键索引外的附加索引结构,用于加速基于非主键列的查询操作。以下是关于二级索引的全面解析: 一、核心概念 特性主键索引 (Primary Index)二级索引 (Secondary Index)唯一性必须唯一可以唯一或非唯一数量每表只有…

Python_level1_字符串_11

目录 一、基本概念 二、字符串基本操作&#xff1a;【索引、切片、遍历】 1.字符串与列表&#xff08;相同&#xff09; 1&#xff09;索引&#xff08;从0开始&#xff09;(可以获取某一个/某几个连续的字符) 2&#xff09;切片 [xx:xx] 与 列表 语法规则一样 [起…

Axure数据可视化科技感大屏设计资料——赋能多领域,展示无限价值

可视化大屏如何高效、直观地展示数据&#xff0c;并将其转化为有价值的决策依据&#xff0c;成为了许多企业和组织面临的共同挑战。Axure大屏可视化模板&#xff0c;作为一款强大的数据展示工具&#xff0c;正在以其出色的交互性和可定制性&#xff0c;赋能多个领域&#xff0c…

MySQL 性能调优:数据库的极限运动训练

就像运动员需要不断训练才能突破极限&#xff0c;数据库也需要各种调优才能跑得更快…让我们一起给 MySQL 安排一套专业的"健身计划"&#xff01; 什么是 MySQL 性能调优&#xff1f;&#x1f914; MySQL 性能调优是指通过各种配置优化、结构调整和查询改进&#x…

4.5/Q1,GBD数据库最新文章解读

文章题目&#xff1a;Emerging trends and cross-country health inequalities in congenital birth defects: insights from the GBD 2021 study DOI&#xff1a;10.1186/s12939-025-02412-7 中文标题&#xff1a;先天性出生缺陷的新趋势和跨国健康不平等&#xff1a;GBD 202…

基于DeepSeek、ChatGPT支持下的地质灾害风险评估、易发性分析、信息化建库及灾后重建

前言&#xff1a; 地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。在降水、地震等自然诱因的作用下&#xff0c;地质灾害在全球范围内频繁发生。我国不仅常见滑坡灾害&#xff0c;还…

Linux | 安装超级终端串口软件连接i.MX6ULL开发板(8)

01 它的安装步骤也非常简单,安装语言选择中文简体,点击确定,如下图所示。 点击下一步,如下图所示。 02

蓝桥杯15届 宝石组合

问题描述 在一个神秘的森林里&#xff0c;住着一个小精灵名叫小蓝。有一天&#xff0c;他偶然发现了一个隐藏在树洞里的宝藏&#xff0c;里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状&#xff0c;但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝…

Lua:第1-4部分 语言基础

1 Lua语言入门 1.1 程序段 我们将 Lua 语言执行的每一段代码&#xff08;例如&#xff0c;一个文件或交互模式下的一行&#xff09;称为一个程序段 &#xff08; Chunk &#xff09; &#xff0c;即一组命令或表达式组成的序列 。 1.2 一些词法规范 Lua 语言中的标识符&#…

CTF类题目复现总结-hashcat 1

一、题目地址 https://buuoj.cn/challenges#hashcat二、复现步骤 1、下载附件&#xff0c;解压得到What kind of document is this_文件&#xff1b; 2、用010 Editor打开What kind of document is this_文件&#xff0c;发现是office文件&#xff1b; 3、将后缀名改为ppt时…

手机归属地查询Api接口,数据准确可靠

手机归属地查询是一项非常实用的功能&#xff0c;它可以帮助我们快速了解一个手机号码的所属地区、区号、邮政编码等信息。在互联网时代&#xff0c;随着大数据和人工智能技术的发展&#xff0c;手机归属地查询的API接口也变得越来越普及和便捷。 在本文中&#xff0c;我们将介…

orangepi zero烧录及SSH联网

下载对应版本的armbian镜像 armbian的默认用户root&#xff0c;默认密码&#xff1a;1234 下载烧录工具win32diskimager https://sourceforge.net/projects/win32diskimager/files/Archive/ 插入16G以上TF卡&#xff0c;使用win32diskimager烧录armbian镜像 烧录完毕后用l…

为什么有的深度学习训练,有训练集、验证集、测试集3个划分,有的只是划分训练集和测试集?

在机器学习和深度学习中&#xff0c;数据集的划分方式取决于任务需求、数据量以及模型开发流程的严谨性。 1. 三者划分&#xff1a;训练集、验证集、测试集 目的 训练集&#xff08;Training Set&#xff09;&#xff1a;用于模型参数的直接训练。验证集&#xff08;Validati…

Linux驱动开发 块设备

目录 序言 1.块设备结构 分区(gendisk) 请求(request) 请求队列 1. 多队列架构 2. 默认限制与扩展 bio 2.块设备的使用 头文件与宏定义 blk-mq 相关结构和操作 块设备操作函数 模块初始化函数 模块退出函数 3.总结 序言 块设备&#xff08;如硬盘、虚拟盘&#x…

ResNet改进(14):添加 EMA注意力机制提升跨空间学习效率

本专栏代码均经过测试,可以直接替换项目中的模型,一键运行! 采用最新的即插即用模块,有效涨点!! 1.EMA注意力机制 EMA(Efficient Multi-scale Attention)注意力机制是一种创新的注意力设计,能够有效提升模型在跨空间学习任务中的表现。以下是对该机制的详细解析: EM…

计算机硬件——CPU 主要参数

什么是 CPU &#xff1f; CPU 的英文全称是 Central Processing Unit&#xff0c;即中央处理器。CPU 的内部结构可分为控制单元、逻辑单元和存储单元三大部分。CPU 的性能大致上反映出了它所配置的微机的性能&#xff0c;因此 CPU 的性能指标十分重要。 CPU 的主要参数 CPU …

针对 Python 3.7.0,以下是 Selenium 版本的兼容性建议和安装步骤

1. Selenium 版本推荐 最高兼容版本&#xff1a; Selenium 4.11.2&#xff08;官方明确支持 Python 3.7&#xff0c;但需注意部分新功能可能受限&#xff09;。 稳定兼容版本&#xff1a; Selenium 3.141.0&#xff08;经典版本&#xff0c;完全兼容 Python 3.7&#xff0c;适…