当前位置: 首页 > 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; …...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...