Linux 信号知识点总结

news2024/10/6 5:54:05

对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号,为 Linux提供了一种处理异步事件的方法。比如,终端用户输入了 ctrl+c 来中断程序,会通过信号机制停止一个程序。
信号概述
1.信号的名字和编号:
每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO“,“SIGCHLD”等等。
信号定义在 signal.h 头文件中,信号名都定义为正整数。

具体的信号名称可以使用 kill -l 来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。 

2.信号的处理:
信号的处理有三种方法,分别是: 忽略、捕捉和默认动作
忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL 和 SIGSTOP )。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景。
捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
具体的信号默认动作可以使用 man 7 signa1 来查看系统的具体定义。在此,我就不详细展开了,需要查看的,可以自行查看。也可以参考 《UNIX 环境高级编程(第三部)》的 P251--P256中间对于每个信号有详细的说明。


了解了信号的概述,那么,信号是如何来使用呢?
其实对于常用的 kill 命令就是一个发送信号的工具, kill 9 PID 来杀死进程。比如,我在后台运行了一个 top 工具,通过 ps 命可以查看他的 PID,通过 kill 9来发送了一个终止进程的信号来结束了 top 进程。如果查看信号编号和名称,可以发现9对应的是 9) SIGKILL,正是杀死该进程的信号。而以下的执行过程实际也就是执行了9号信号的默认动作一一杀死进程。

先ps -aux|grep a.out 查看pid为61672

再杀死进程

可以编写捕捉信号代码,例如按ctrl c 捕捉这个信号是什么,不停止程序,代码如下:

编译结果:

(代码可复制):

#include <signal.h>
#include <stdio.h>

//       typedef void (*sighandler_t)(int);

//       sighandler_t signal(int signum, sighandler_t handler);

void handler(int signum)
{
    printf("get signum=%d\n",signum);
    switch(signum){
        case 2:
            printf("SIGINT\n");
            break;
        case 9:
            printf("SIGKILL\n");
            break;
        case 10:
            printf("SIGUSR1\n");
            break;

    }


    printf("never quit\n");
}

int main()
{
    signal(SIGINT,handler);
    signal(SIGKILL,handler);
    signal(SIGUSR1,handler);
    while(1);
    return 0;
}

那么我们还可以编写一段代码来用对应数字表示各种信号宏

vi pro.c

运行结果:gcc pro.c -o pro 

(代码可复制)

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>


int main(int argc ,char **argv)
{
    int signum;
    int pid;

    char cmd[128]={0};

    signum = atoi(argv[1]);
    pid = atoi(argv[2]);

    printf("num=%d,pid=%d\n",signum,pid);    

//    kill(pid, signum);
    sprintf(cmd,"kill -%d %d",signum,pid);

    
    system(cmd);

    printf("send signal ok");    
    return 0;
}

既然可以编写捕捉信号代码,那么也可以忽略信号,只需要改一个地方:

编译结果: 信号被忽略了

信号注册函数一高级版


我们已经成功完成了信号的收发,那么为什么会有高级版出现呢? 其实之前的信号存在一个问题就是,虽然发送和接收到了信号,可是总感觉少些什么,既然都已经把信号发送过去了,为何不能再携带一些数据呢?正是如此,我们需要另外的函数来通过信号传递的过程中,携带一些数据。咱么先来看看发送的函数吧。
sigaction 的函数原型

头文件:

 #include <signal.h>

函数原型:
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

可以通过 man sigaction 来查看这个函数的原版帮助信息。
sigaction 是一个系统调用,根据这个函数原型,我们不难看出,在函数原型中,第一个参数signum 应该就是注册的信号的编号;第二个参数at 如果不为空说明需要对该信号有新的配置;第三个参数oldact 如果不为空,那么可以对之前的信号配置进行备份,以方便之后进行恢复。

在这里额外说一下struct sigaction 结构体中的 sa_mask 成员,设置在其的信号集中的信号,会在捕捉函数调用前设置为阻塞,并在捕捉函数返回时恢复默认原有设置。这样的目的是,在调用信号处理函数时,就可以阻塞默写信号了。在信号处理函数被调用时,操作系统会建立新的信号阻塞字,包括正在被递送的信号。因此,可以保证在处理一个给定信号时,如果这个种信号再次发生,那么他会被阻塞到对之前一个信号的处理结束为止。
sigaction 的时效性: 当对某一个信号设置了指定的动作的时候,那么,直到再次显式调用sigaction并改变动作之前都会一直有效
关于结构体中的 flag 属性的详细配置,在此不做详细的说明了,只说明其中一点。如果设置为 SA_ SIGINFO 属性时,说明了信号处理程序带有附加信息,也就是会调用sa sigaction 这个函数指所指向的信号处理函数。否则,系统会默认使用 sa_handler所指向的信号处理函数。在此,还要特别说明一下,sa_sigaction 和 sa_handler 使用的是同一块内存空间,相当于 union,所以只能设置其中的一个,不能两个都同时设置。
关于void (*sa _sigaction)(int,siginfo_t *,void *);处理函数来说还需要有一些说明.void*是接收到信号所携带的额外数据;而struct siginfo这个结构体主要适用于记录接收信号的一些相关信息。

 其中的成员很多,si_signo 和 si_code 是必须实现的两个成员。可以通过这个结构体获取到信号的相关信息。
关于发送过来的数据是存在两个地方的,sigval_t si_value这个成员中有保存了发送过来的信息;同时,在si_int或者si_ptr成员中也保存了对应的数据。
那么,kil 函数发送的信号是无法携带数据的,我们现在还无法验证发送收的部分,那么,我们先来看看发送信号的高级用法后,我们再来看看如何通过信号来携带数据吧。

信号发送函数--高级版

使用这个函数之前,必须要有几个操作需要完成
1.使用 sigaction 函数安装信号处理程序时,制定了 SA_SIGINFO 的标志
2.sigaction 结构体中的 sa_sigaction 成员提供了信号捕捉函数。如果实现的时sa_handler 成员,那么将无法获取额外携带的数据。
sigqueue 函数只能把信号发送给单个进程,可以使用 value 参数向信号外理程序传递整数值或者指针值。
sigqueue 函数不但可以发送额外的数据,还可以让信号进行排队 (操作系统必须实现了POSIX.1的实时扩展),对于设置了阻塞的信号,使用 sigqueue 发送多个同一信号,在解除阻塞时,接受者会接收到发送的信号队列中的信号,而不是直接收到一次。

代码实例:

vi nicesig.c

vi send.c:

编译结果:

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

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

相关文章

JavaSE_day38(异常分类,自定义异常,File介绍,方法使用,相对路径与绝对路径概念以及注意的点)

1 A.java * 异常的分类&#xff1a; 运行时期异常:RuntimeException的子类就是运行时期异常&#xff0c;在编译时期可以自由选择处理或者不处理 编译时期异常:是Exception的子类&#xff0c;非RuntimeExcpetion的子类&#xff0c;在编译时期必须处理 public c…

注意力机制(一)SE模块(Squeeze-and-Excitation Networks)

Squeeze-and-Excitation Networks&#xff08;压缩和激励网络&#xff09; 论文地址&#xff1a;Squeeze-and-Excitation Networks 论文中文版&#xff1a;Squeeze-and-Excitation Networks_中文版 代码地址&#xff1a;GitHub - hujie-frank/SENet: Squeeze-and-Excitation Ne…

chatgpt赋能python:Python内置:优化SEO的利器?

Python 内置&#xff1a;优化SEO的利器&#xff1f; Python是一种广泛使用的高级编程语言&#xff0c;拥有丰富的标准库和第三方库&#xff0c;能够适用于很多领域。其中&#xff0c;Python内置的一些功能&#xff0c;比如字符串操作和网络请求&#xff0c;可以帮助我们进行SE…

web前端综合案例——小兔鲜首页(html+css)

前言&#xff1a;我这里只使用了html和css&#xff0c;js没有使用 项目源代码&#xff1a;https://pan.baidu.com/s/1alnekYEu5F9XwHTW7dO5RA?pwdqjhd 页面效果&#xff1a; 项目准备阶段&#xff1a; 1.准备项目相应的图片素材&#xff0c;设计稿。 2.创建项目: 2.1 项目…

用反射设计通用的实例化对象方案

需求 对象的相关信息存储在javabean.properties文件中&#xff0c;通过读取properties文件中的信息&#xff0c;实例化对象&#xff0c;要求程序不能硬编码&#xff0c;即程序可以通用&#xff0c;针对不同的对象&#xff0c;都可以实例化。仅需修改配置文件&#xff0c;不需要…

网络基础初识

目录 网络发展 时代背景 计算机内部 协议 协议的创立 什么是协议&#xff1f; 网络协议 OSI七层模型 TCP/IP五层(或四层)模型 硬件方面 -- 补充 路由器 协议的分层 网络传输基本流程 1.协议报头 2.局域网 查询自己的MAC地址 局域网通信的原理 跨路由器传递数…

以太网协议详解

文章目录 前言一、MAC地址二、以太网协议1. 以太网数据格式2. MAC地址表 前言 假设有这样一张网络拓扑图&#xff1a; 在拓扑图中有A、B、C三台计算机&#xff0c;并且它们三个是通过中间的路由器连接的。这时候计算机A要向计算机C发送一条数据&#xff0c;那么数据是怎么样到…

nvm教程

介绍 这个东西&#xff0c;是nodejs官网有个链接里面有很多列表&#xff0c;这是其中一个 下载 https://github.com/coreybutler/nvm-windows/releases 安装 安装前&#xff0c;将.npmrc文件删除&#xff1b;文件位置&#xff1a; C:\Users{User}\AppData\Roaming\npm C:\…

chatgpt赋能python:Python单行for:如何简化你的代码

Python单行for&#xff1a;如何简化你的代码 在Python编程中&#xff0c;for循环是必不可少的一部分&#xff0c;它可以用于遍历列表、元组和字典等各种数据类型。而Python单行for则是一种更加简单、更加紧凑的语法形式&#xff0c;可以让你更加高效地遍历和处理数据。 什么是…

STL--mapset(手撕AVL树,红黑树)

1. 关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、 forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面 存储的是元素本身。那什么是关…

Yolov5涨点神器:注意力机制---多头上下文集成(Context Aggregation)的广义构建模块,助力小目标检测,暴力涨点

1.数据集性能验证 在crack道路缺陷检测任务中,多头上下文集成(Context Aggregation)的广义构建模块实现暴力涨点mAP50从0.954提升至0.992 🏆🏆🏆🏆🏆🏆Yolov5/Yolov7魔术师🏆🏆🏆🏆🏆🏆 ✨✨✨魔改网络、复现前沿论文,组合优化创新 🚀🚀🚀…

内网渗透(八十三)之安装ADCS证书服务

安装ADCS证书服务 本编文章,我们来讲解安装ADCS证书服务,这里注意一下,因为证书服务特性(不能更改计算机名称、网络参数),因此在部署证书服务器时建议独立部署,ADCS证书服务不能和域控是同一台服务器,这里我用的一台加入域的Server2016搭建 1、以 Enterprise Admins …

chatgpt赋能python:Python内置变量的重要性及常用变量介绍

Python内置变量的重要性及常用变量介绍 Python是一种简单易学的脚本语言&#xff0c;其特点是直观、易读、代码简单且易维护。Python内置变量是开发人员在Python编程中必不可少的一部分&#xff0c;它们在程序中扮演着重要的角色。接下来我们来介绍一些常用的Python内置变量。…

chatgpt赋能python:Python的内部类:优雅的封装性与灵活的应用

Python的内部类&#xff1a;优雅的封装性与灵活的应用 Python的内部类是面向对象编程中强大的封装性工具&#xff0c;它在类的内部定义其他类来辅助实现某些功能&#xff0c;可以有效避免类命名冲突、提高代码灵活性等。本文将详细介绍Python内部类的特点及应用场景&#xff0…

chatgpt赋能python:Python单行判断:提高代码效率的利器

Python单行判断&#xff1a;提高代码效率的利器 在Python编程中&#xff0c;单行判断是常用的一种技巧。相比使用if语句&#xff0c;单行判断可以让代码更加简洁、优美&#xff0c;提高代码的效率和可读性。本文将介绍Python单行判断的用法及其优势&#xff0c;帮助读者更好地…

【2023年第三届长三角高校数学建模竞赛】A 题 快递包裹装箱优化问题 20页完整论文及代码

相关链接 【2023年第三届长三角高校数学建模竞赛】A 题 快递包裹装箱优化问题 详细数学建模过程 1 题目 2022 年&#xff0c;中国一年的包裹已经超过 1000 亿件&#xff0c;占据了全球快递事务量的一半以上。近几年&#xff0c;中国每年新增包裹数量相当于美国整个国家一年的…

基于SpringBoot的留守儿童爱心网站的设计与实现

背景 随着留守儿童爱心管理的不断发展&#xff0c;留守儿童爱心网站在现实生活中的使用和普及&#xff0c;留守儿童爱心管理成为近年内出现的一个热门话题&#xff0c;并且能够成为大众广为认可和接受的行为和选择。设计留守儿童爱心网站的目的就是借助计算机让复杂的管理操作…

如何从Ubuntu Linux中删除Firefox Snap?

Ubuntu Linux是一款广受欢迎的开源操作系统&#xff0c;拥有强大的功能和广泛的应用程序选择。默认情况下&#xff0c;Ubuntu提供了一种称为Snap的软件打包格式&#xff0c;用于安装和管理应用程序。Firefox是一款流行的开源网络浏览器&#xff0c;而Firefox Snap是Firefox的Sn…

<Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的LED驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -之-基于pinctrl/gpio子系统的LED驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 u…

chatgpt赋能python:Python二维码解码-从介绍到结论

Python 二维码解码 - 从介绍到结论 二维码在现代数字化时代的应用越来越普及&#xff0c;它能够快速、准确地扫描并解码大量的信息。Python作为一种流行的通用编程语言&#xff0c;已经成为开发人员首选的工具之一&#xff0c;为我们解码二维码提供了强大的支持。本篇SEO文章将…