当前位置: 首页 > news >正文

进程间通信——信号

信号的概念

  • 信号是 Linux进程间通信的最古老的方式之一,是事件发生时对进程的通知机制,有时也称之为软件中断,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突发事件。
  • 发往进程的诸多信号,通常都是源于内核。引发内核为进程产生信号的各类事件如下:

----◼ 对于前台进程,用户可以通过输入特殊的终端字符来给它发送信号。比如输入Ctrl+C 通常会给进程发送一个中断信号。

----◼ 硬件发生异常,即硬件检测到一个错误条件并通知内核,随即再由内核发送相应信号给相关进程。比如执行一条异常的机器语言指令,诸如被 0 除,或者引用了无法访问的内存区域。

----◼ 系统状态变化,比如 alarm 定时器到期将引起 SIGALRM 信号,进程执行的 CPU 时间超限,或者该进程的某个子进程退出。

----◼ 运行 kill 命令或调用 kill 函数。

使用信号的两个主要目的是:

----◼ 让进程知道已经发生了一个特定的事情。

----◼ 强迫进程执行它自己代码中的信号处理程序。

信号的特点:

----◼ 简单

----◼ 不能携带大量信息

----◼ 满足某个特定条件才发送

----◼ 优先级比较高

查看系统定义的信号列表:kill –l

前 31 个信号为常规信号,其余为实时信号。

Linux 典型信号

编号信号名称对应事件默认动作
2SIGINT当用户按下了组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号终止进程
3SIGQUIT用户按下组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出些信号终止进程
9SIGKILL无条件终止进程。该信号不能被忽略,处理和阻塞终止进程,可以杀死任何进程
11SIGSEGV指示进程进行了无效内存访问(段错误)终止进程并产生core文件
13SIGPIPEBroken pipe 向一个没有读端的管道写数据终止进程
17SIGCHLD子进程结束时,父进程会收到这个信号忽略这个信号
18SIGCONT如果进程已停止,则使其继续运行继续/忽略
19SIGSTOP停止进程的执行。信号不能被忽略,处理和阻塞为终止进程

信号的 5 种默认处理动作

查看信号的详细信息:man 7 signal
信号的 5 种默认处理动作
----◼ Term 终止进程

----◼ Ign 当前进程忽略掉这个信号

----◼ Core 终止进程,并生成一个 Core 文件用来保存进程异常退出的错误信息

----◼ Stop 暂停当前进程

----◼ Cont 继续执行当前被暂停的进程

信号的几种状态:产生、未决、递达

SIGKILL 和 SIGSTOP 信号不能被捕捉、阻塞或者忽略,只能执行默认动作。

信号相关的函数

kill 函数

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

作用:给任何的进程或者进程组发送任何的信号(sig)

参数:
---- pid:
-------- > 0:将信号发送给指定的进程
-------- = 0:将信号发送给当前的进程组
-------- = -1:将信号发送给每一个有权限接受这个信号的进程
-------- < -1:这个 pid 就是某个进程组的 ID 的相反数,给这个进程组发送信号
------- sig:需要发送的信号的编号或者是宏值,0 表示不发送任何信号

例子:

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>int main()
{pid_t pid = fork();if (pid == 0) {//子进程for (int i = 0; i < 5; ++i) {printf("child \n");sleep(1);}}else if (pid > 0) {//父进程printf("parent\n");sleep(2);printf("kill child\n");kill(pid, 9);}return 0;
}

raise 函数

#include <signal.h>
int raise(int sig);

作用:给当前进程发送信号
参数:要发送的信号
返回:成功返回 0,失败返回非 0
等价于:kill(getpid(), sig);

abort 函数

#include <stdlib.h>
void abort(void);

作用:发送 SIGABORT 信号给当前进程,杀死当前进程
等价于:kill(getpid(), SIGABORT);

alarm 函数

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

作用:设置定时器(闹钟),函数调用开始倒计时,当倒计时为 0 的时候,函数会给当前的进程发送一个信号:SIGALRM 默认终止当前的进程,每一个进程都有且只有唯一的一个定时器。

参数:倒计时的时长,单位是秒,参数为 0 表示定时器无效(不进行倒计时,不发信号)。可以通过传递 0 参数来取消一个定时器。

返回:

---- 之前没有定时器:返回 0

---- 之前有定时器:返回之前的定时器倒计时剩余时间

alarm 与进程的状态(运行、阻塞等)无关。

首先设置一个 5 秒的定时器,之后修改为 10 秒,过了 10 秒时候发送 SIGALRM 信号默认关闭进程:

#include <unistd.h>
#include <stdio.h>int main()
{int seconds = alarm(5);printf("seconds = %d\n", seconds);sleep(2);seconds = alarm(10);printf("seconds = %d\n", seconds);while (1) {}return 0;
}

在这里插入图片描述
setitimer 函数

#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_val, struct itimerval *old_value);

作用:设置定时器,可以替代 alarm 函数。精度是微秒(us)。

参数:

---- which:定时器以什么时间定时

-------- ITIMER_REAL:真实时间,时间到达后发送 SIGALRM ,是最常用的

-------- ITIMER_VIRTUAL:用户时间,时间到达后发送 SIGVTALRM

-------- ITIMER_PROF:以该进程在用户态和内核态下所消耗的时间来计算,时间到达后发送 SIGPROF

---- new_val:设置定时器的属性

struct itimerval {  //定时器结构体struct timeval it_interval;  //每个阶段的时间,间隔时间struct timeval it_value;  //延迟多长时间执行定时器
};
struct timeval {  //时间的结构体time_t      tv_sec;  //秒数suseconds_t tv_usec;  //微秒
};

---- old_value:记录上一次的定时的时间参数,一般不使用,指定 NULL

返回:成功返回 0,失败返回 -1

信号捕捉函数 signal 函数

#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler); 

作用:设置某个信号的捕捉行为

参数:

---- signum:要捕捉的信号

---- handler:捕捉到信号要如何处理

-------- SIG_IGN:忽略信号

-------- SIG_DFL:使用信号默认的行为

-------- 回调函数:函数指针类型,由内核调用,程序员只负责提前写好捕捉到信号后如何处理信号

返回:

---- 成功:返回上一次注册的信号处理函数的地址。第一次调用返回 NULL

---- 失败:返回 SIG_ERR,设置错误号

过3秒之后定时开始,每隔2秒钟定时一次的示例:

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>void myalarm(int num)
{printf("捕捉到了的信号的编号是:%d\n", num);printf("xxxxxx\n");
}int main()
{//注册信号捕捉__sighandler_t ret0 = signal(SIGALRM, myalarm);if (ret0 == SIG_ERR) {perror("signal");exit(0);}struct itimerval new_value;//设置间隔时间new_value.it_interval.tv_sec = 2;new_value.it_interval.tv_usec = 0;//设置延迟时间new_value.it_value.tv_sec = 3;new_value.it_value.tv_usec = 0;int ret = setitimer(ITIMER_REAL, &new_value, NULL);printf("定时器开始了\n");if (ret == -1) {perror("setitimer");exit(0);}getchar();return 0;
}

程序三秒之后输出“定时器开始了”,然后每隔两秒输出后面的内容
在这里插入图片描述

信号集

  • 许多信号相关的系统调用都需要能表示一组不同的信号,多个信号可使用一个称之为信号集的数据结构来表示,其系统数据类型为 sigset_t。
  • 在 PCB 中有两个非常重要的信号集。一个称之为 “阻塞信号集” ,另一个称之为“未决信号集” 。这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对这两个信号集进行位操作。而需自定义另外一个集合,借助信号集操作函数来对PCB 中的这两个信号集进行修改。
  • 信号的 “未决” 是一种状态,指的是从信号的产生到信号被处理前的这一段时间。 信号的 “阻塞”是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生。信号的阻塞就是让系统暂时保留信号留待以后发送。由于另外有办法让系统忽略信号,所以一般情况下信号的阻塞只是暂时的,只是为了防止信号打断敏感的操作。

阻塞信号集和未决信号集:

  1. 用户通过键盘 Ctrl + C, 产生 2 号信号 SIGINT (信号被创建)

  2. 信号产生但是没有被处理 (未决)

     ---- 在内核中将所有的没有被处理的信号存储在一个集合中 (未决信号集)---- SIGINT 信号(2 号信号)状态被存储在第二个标志位上---- 如果这个标志位的值为 0, 说明信号不是未决状态---- 如果这个标志位的值为 1, 说明信号处于未决状态
    
  3. 这个未决状态的信号,需要被处理,处理之前需要和另一个信号集(阻塞信号集),进行比较

     ---- 阻塞信号集默认不阻塞任何的信号---- 如果想要阻塞某些信号需要用户调用系统的 API
    
  4. 在处理的时候和阻塞信号集中的标志位进行查询,看是不是对该信号设置阻塞了

     ---- 如果没有阻塞,这个信号就被处理---- 如果阻塞了,这个信号就继续处于未决状态,直到阻塞解除,这个信号就被处理
    

以下信号集相关的函数都是对自定义的信号集进行操作:

int sigemptyset(sigset_t *set);
  • 作用:清空信号集中的数据,将信号集中的所有的标志位置为 0
  • 参数:set,值-结果参数,需要操作的信号集
  • 返回:成功返回 0, 失败返回 -1
int sigfillset(sigset_t *set);
  • 作用:将信号集中的所有的标志位置为 1
  • 参数:set,值-结果参数,需要操作的信号集
  • 返回值:成功返回0, 失败返回 -1
int sigaddset(sigset_t *set, int signum);
  • 作用:设置信号集中的某一个信号对应的标志位为 1,表示阻塞这个信号 参数:
  • ---- set:值-结果参数,需要操作的信号集
  • ---- signum:需要设置阻塞的那个信号
  • 返回:成功返回 0, 失败返回 -1
int sigdelset(sigset_t *set, int signum);
  • 作用:设置信号集中的某一个信号对应的标志位为 0,表示不阻塞这个信号 参数:
  • ---- set:值-结果参数,需要操作的信号集
  • ---- signum:需要设置不阻塞的那个信号
  • 返回:成功返回 0, 失败返回 -1
int sigismember(const sigset_t *set, int signum);
  • 作用:判断某个信号是否阻塞

参数:

  • ---- set:需要操作的信号集
  • ---- signum:需要判断的那个信号

返回:

  • ---- 1 : signum被阻塞
  • ---- 0 : signum不阻塞
  • ---- -1 : 失败
    示例:
#include <signal.h>
#include <stdio.h>int main()
{//创建一个信号集sigset_t set;//清空信号集的内容sigemptyset(&set);//判断 SIGINT 是否在信号集 set 里int ret = sigismember(&set, SIGINT);if (ret == 0) {printf("SIGINT不阻塞\n");}else if (ret == 1) {printf("SIGINT阻塞\n");}//添加信号到信号集中sigaddset(&set, SIGINT);ret = sigismember(&set, SIGINT);if (ret == 0) {printf("SIGINT不阻塞\n");}else if (ret == 1) {printf("SIGINT阻塞\n");}//从信号集中删除一个信号sigdelset(&set, SIGINT);ret = sigismember(&set, SIGINT);if (ret == 0) {printf("SIGINT不阻塞\n");}else if (ret == 1) {printf("SIGINT阻塞\n");}return 0;
}

在这里插入图片描述
sigprocmask 函数

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • 作用:将自定义信号集中的数据设置到内核中(设置阻塞,解除阻塞,替换)

  • 参数:

    ---- how :如何对内核阻塞信号集进行处理

    -------- SIG_BLOCK::将用户设置的阻塞信号集添加到内核中,内核中原来的数据不变,mask | set

    -------- SIG_UNBLOCK::根据用户设置的数据,对内核中的数据进行解除阻塞 mask &= ~set

    -------- SIG_SETMASK:覆盖内核中原来的值

    ---- set :已经初始化好的用户自定义的信号集

    ---- oldset : 保存设置之前的内核中的阻塞信号集的状态,可以是 NULL

  • 返回:成功返回 0,失败返回 -1 并设置错误号 EFAULT、EINVAL

SIGKILL 和 SIGSTOP 不能被捕捉,不能被忽略。

内核实现信号捕捉的过程

在这里插入图片描述

相关文章:

进程间通信——信号

信号的概念 信号是 Linux进程间通信的最古老的方式之一&#xff0c;是事件发生时对进程的通知机制&#xff0c;有时也称之为软件中断&#xff0c;它是在软件层次上对中断机制的一种模拟&#xff0c;是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异…...

PAT 1039 Course List for Student

个人学习记录&#xff0c;代码难免不尽人意。 Zhejiang University has 40000 students and provides 2500 courses. Now given the student name lists of all the courses, you are supposed to output the registered course list for each student who comes for a query. …...

【Sklearn】基于决策树算法的数据分类预测(Excel可直接替换数据)

【Sklearn】基于决策树算法的数据分类预测(Excel可直接替换数据) 1.模型原理1.1 模型原理1.2 数学模型2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果1.模型原理 决策树是一种基于树状结构的分类和回归模型,它通过一系列的决策规则来将数据划分为不同的类…...

并发编程4:Java 中的并发基础构建模块

目录 1、同步容器类 1.1 - 同步容器类的问题 1.2 - 迭代和容器加锁 2、并发容器类 2.1 - ConcurrentHashMap 类 2.2 - CopyOnWriteArrayList 类 3、阻塞队列和生产者-消费者模式 3.1 - 串行线程封闭 4、阻塞方法与中断方法 5、同步工具类 5.1 - 闭锁 -> CountDow…...

Vue-10.集成(.editorconfig、.eslintrc.js、.prettierrc)

介绍 同时使用 .editorconfig、.prettierrc 和 .eslintrc.js 是很常见的做法&#xff0c;因为它们可以在不同层面上帮助确保代码的格式一致性和质量。这种组合可以在开发过程中提供全面的代码维护和质量保证。然而&#xff0c;这也可能增加一些复杂性&#xff0c;需要谨慎配置…...

PHP-FPM进程排查

1、查看php-fpm的进程个数 ps -ef |grep "php-fpm"|grep "pool"|wc -l2、查看每个php-fpm占用的内存大小 ps -ylC php-fpm --sort:rss3.查看PHP-FPM在你的机器上的平均内存占用 ps --no-headers -o "rss,cmd" -C php-fpm | awk { sum$1 } END…...

PHP-MD5注入

0x00 前言 有些零散的知识未曾关注过&#xff0c;偶然捡起反而更加欢喜。 0x01 md5 注入绕过 md5函数有两个参数&#xff0c;第一个参数是要进行md5的值&#xff0c;第二个值默认为false&#xff0c;如果为true则返回16位原始二进制格式的字符串。意思就是会将md5后的结果当…...

对redis、redisson、springcache总结

<一> redis-缓存中间件 什么是redis redis是c语言开发的&#xff0c;一个高性能key-value键值对内存数据库&#xff0c;可以用来做数据库、缓存、消息中间件的一种非关系型数据库。 redis数据存储在哪里 内存和磁盘中&#xff0c;但是redis的读写都在内存中&#xff0c;…...

Java基础知识实际应用(学生信息管理系统、猜拳小游戏、打印日历)

一、Java学生信息管理系统 这个系统包含了添加、修改、删除、查询和显示所有学生信息等功能。您可以在此基础上进行修改和完善&#xff0c;以适应您的需求。 import java.util.Scanner;public class StudentManagementSystem {private static Scanner scanner new Scanner(S…...

Git:在本地电脑上如何使用git?

git 版本&#xff1a; 2.40.1.windows.1 文章目录 一. 使用git之前你必须要理解的几个概念1.1 理解工作区、版本库、暂存区的概念1.2 提交Git版本库的步骤【分两步执行】 二. Git本地库实战2.1 初始化版本库2.2 新建 & 提交 & 状态2.3 查看日志2.4 回退 & 穿梭 &am…...

卷和分区的关系

1、分区 存储空间管理和仓库管理类似&#xff0c;只不过仓库管理的是货物&#xff0c;存储空间管理的是文件。当仓库规模小时&#xff0c;可以不划分货物的存放区域&#xff0c;但当仓库规模很大&#xff0c;就必须根据货物的类型和存储需要&#xff0c;把仓库分为多个区域。例…...

Linux下在qtcreator中创建qt程序

目录 1、新建项目 2、单工程项目创建 3、多工程项目创建 4、添加子工程&#xff08;基于多工程目录结构&#xff09; 5、 .pro文件 1、新建项目 切换到“编辑”界面&#xff0c;点击菜单栏中的“文件”-“新建文件或项目” 2、单工程项目创建 只有一个工程的项目&#…...

快递再多也不怕!你的顺丰快递用上5G“神器”

互联网时代&#xff0c;剁手党疯狂“买买买”之后&#xff0c;快递件量再创新高。《2023年6月中国快递发展指数报告》显示&#xff0c;2023二季度单月快递业务量稳定在百亿件以上。其中&#xff0c;由于“618”电商促销活动与父亲节叠加&#xff0c;6月16日至20日单日揽收量均超…...

微信小程序:模板使用

目录 模板的优点&#xff1a; 一、静态模板创建 二、静态模板使用 1.*.wxml引入模板 2.模板使用 3.*.wxss引入模板的样式 三、动态模板创建 四、动态模板使用 1.*.wxml引入模板 2.模板使用 3.*.js定义动态数据 五、结果展示 总结 模板的优点&#xff1a; 有利于保持网…...

AUTOSAR NvM Block的三种类型

Native NVRAM block Native block是最基础的NvM Block&#xff0c;可以用来存储一个数据&#xff0c;可以配置长度、CRC等。 Redundant NVRAM block Redundant block就是在Native block的基础上再加一个冗余块&#xff0c;当Native block失效&#xff08;读取失败或CRC校验失…...

Vue+ElementUI实现选择指定行导出Excel

这里记录一下&#xff0c;今天写项目时 的一个需求&#xff0c;就是通过复选框选中指定行然后导出表格中选中行的Excel表格 然后这里介绍一个工具箱(模板)&#xff1a;vue-element-admin 将它拉取后&#xff0c;运行就可以看到如下界面&#xff1a; 这里面的很多功能都已经实现…...

SNMP简单介绍

SNMP SNMP是广泛应用于TCP/IP网络的网络管理标准协议&#xff0c;该协议能够支持网络管理系统&#xff0c;用以监测连接到网络上的设备是否有任何引起管理上关注的情况。SNMP采用轮询机制&#xff0c;提供最基本的功能集&#xff0c;适合小型、快速、低价格的环境使用&#xf…...

使用python对图像加噪声

加上雨点噪声 import cv2 import numpy as npdef get_noise(img, value10):#生成噪声图像>>> 输入&#xff1a; img图像value 大小控制雨滴的多少 >>> 返回图像大小的模糊噪声图像noise np.random.uniform(0, 256, img.shape[0:2])# 控制噪声水平&#xff…...

以 Java NIO 的角度理解 Netty

文章目录 前言Java NIO 工作原理Selector 的创建ServerSocketChannel 的创建ServerSocketChannel 注册 Selector对事件的处理总结 前言 上篇文章《Netty 入门指南》主要涵盖了 Netty 的入门知识&#xff0c;包括 Netty 的发展历程、核心功能与组件&#xff0c;并且通过实例演示…...

Maven自定义脚手架(多module模块)+自定义参数

脚手架 视频教程&#xff1a; Maven保姆级教程 脚手架是一个项目模板&#xff0c;包含常用的工程结构、代码。 1 自定义脚手架 脚手架创建的步骤如下&#xff0c;先创建一个工程&#xff0c;把常用的代码写好&#xff0c;进入工程根目录&#xff0c;进行如下操作&#xff1a; …...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

vue3 手动封装城市三级联动

要做的功能 示意图是这样的&#xff0c;因为后端给的数据结构 不足以使用ant-design组件 的联动查询组件 所以只能自己分装 组件 当然 这个数据后端给的不一样的情况下 可能组件内对应的 逻辑方式就不一样 毕竟是 三个 数组 省份 城市 区域 我直接粘贴组件代码了 <temp…...

TMC2226超静音步进电机驱动控制模块

目前已经使用TMC2226量产超过20K,发现在静音方面做的还是很不错。 一、TMC2226管脚定义说明 二、原理图及下载地址 一、TMC2226管脚定义说明 引脚编号类型功能OB11电机线圈 B 输出 1BRB2线圈 B 的检测电阻连接端。将检测电阻靠近该引脚连接到地。使用内部检测电阻时,将此引…...

AIGC 基础篇 Python基础 02

1.bool类型 书接上回&#xff0c;我们上次最后讲了三大数据类型&#xff0c;除了这三个之外&#xff0c;Python也有bool类型&#xff0c;也就是True和False。 a 2 print(a1) print(a2) 像这里&#xff0c;输出的内容第一个是False&#xff0c;因为a的值为2&#xff0c;而第…...

DOM(文档对象模型)深度解析

DOM(文档对象模型)深度解析 DOM 是 HTML/XML 文档的树形结构表示,提供了一套让 JavaScript 动态操作网页内容、结构和样式的接口。 一、DOM 核心概念 1. 节点(Node)类型 类型值说明示例ELEMENT_NODE1元素节点<div>, <p>TEXT_NODE3文本节点元素内的文字COMMEN…...