[linux]信号处理:信号编码、基本API、自定义函数和集合操作的详解

news2024/9/28 3:26:19

一、信号的概述 

1、定义 

        信号是 Linux 进程间通信的最古老的方式。信号是软件中断,它是在软件层次 上对中断机制的一种模拟,是一种异步(不等待)通信的方式 。信号可以导致一个正在运行的进程被 另一个正在运行的异步进程中断,转而处理某一个突发事件。

        信号的特点 简单 不能携带大量信息 满足某个特设条件才发送。 

      (进程间通信方式:无名管道、无名管道、消息队列、共享内存)

 一个完整的信号周期包括三个部分:

  1. 信号的产生,
  2. 信号在进程中的注册, 信号在进程中的注销,
  3. 执行信号处理函数

        注意:这里信号的产生,注册,注销是信号的内部机制,而不是信号的函数实现。

2、信号的编号

         其中1-31号信号称之为常规信号(也叫普通信号或标准信号),34-64称之为实时信号,驱 动编程与硬件相关。名字上区别不大。而前32个名字各不相同

        每个信号必备4要素,分别是:编号 、名称 、事件 、默认处理动作。可通过man 7 signal查看帮助文档。

Action默认动作

  • Term:终止进程
  • Ign:忽略信号(默认即时对该种信号忽略操作]
  • Core:终止进程,生成Core 文件。(查验死亡原因,用于gdb调试)
  • Stop:停止(暂停)进程
  • Cont:继续运行进程注意

3、 发起信号的方式

  1. 当用户按某些终端键时,将产生信号,如“ctrl+c”、“ctrl+z”
  2. 硬件异常将产生信号。 除数为 0,无效的内存访问等
  3. 软件异常将产生信号(如定时器)
  4. 调用系统函数(如:kill、raise、abort)将发送信号
  5. 运行 kill /killall命令将发送信号

二、未决信号集、信号阻塞集 

        未决信号集:信号发生 但未被处理的信号集合。(放在PCB中)

        信号阻塞集:加入信号阻塞集的信号 不被处理。(放在PCB中)

三、 信号的API

1、kill函数 

#include<sys/types.h>

#include<signal.h>

int kill(pid_t pid, int sig);

功能:给指定进程发送指定信号(不一定杀死)

参数:

        pid : 取值有 4 种情况 :

                pid > 0: 将信号传送给进程 ID 为pid的进程。

                pid = 0 : 将信号传送给当前进程所在进程组中的所有进程。

                pid = -1 : 将信号传送给系统内所有的进程。

                pid < -1 : 将信号传给指定进程组的所有进程。这个进程组号等于 pid 的绝对值。

        sig : 信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令 kill - l("l" 为字母)进行相应查看。不推荐直接使用数字,应使用宏名,因为不同操作系统信号编号可能不同,但名称一致。

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

        super用户(root)可以发送信号给任意用户,普通用户是不能向系统用户发送信号的。同样,普通用户也不能向其他普通用户发送信号,终止其进程。只能向自己创建的进程发送信号。

2、 raise函数 

        #include<signal.h>

        int raise(int sig);  

 功能:给当前进程发送指定信号(自己给自己发),等价于 kill(getpid(), sig)

参数: sig:信号编号

返回值: 成功:0 失败:非0值

3、abort函数

        #include<stdlib.h>

        void abort(void);  

功能:给自己发送异常终止信号 6 SIGABRT,并产生core文件,等价于kill(getpid(), SIGABRT); 参数:无 返回值:无 

 4、alarm函数(闹钟)

        #include<unistd.h>

        unsigned int alarm(unsigned int seconds);  

         功能: 设置定时器(闹钟)。在指定seconds后,内核会给当前进程发送14)SIGALRM信号。进程收到该信号,默认动作终止。每个进程都有且只有唯一的一个定时器。 取消定时器alarm(0)返回旧闹钟余下秒数

        参数: seconds:指定的时间,以秒为单位

        返回值: 返回0或剩余的秒数 定时,与进程状态无关(自然定时法)!就绪、运行、挂起(阻塞、暂停)、终止、僵尸……无论 进程处于何种状态,alarm都计时

 5、setitimer函数(定时器)

#include<sys/time.h>

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);  

功能: 设置定时器(闹钟)。 可代替alarm函数。精度微秒us,可以实现周期定时。 

参数:

which:指定定时方式

  1.  自然定时:ITIMER_REAL 14)SIGALRM计算自然时间
  2. 虚拟空间计时(用户空间):ITIMER_VIRTUAL26)SIGVTALRM 只计算进程占用cpu的时间
  3. 运行时计时(用户 + 内核):ITIMER_PROF27)SIGPROF计算占用cpu及执行系统调用的时间

new_value:struct itimerval, 负责设定timeout时间

struct itimerval {

        struct timerval it_value; // 闹钟触发时间,设定第一次执行function所延迟的秒数

        struct timerval it_interval; // 闹钟触发周期,设定以后每几秒执行function

};

struct timerval {

        long tv_sec; // 秒

        long tv_usec; // 微秒

} ;

old_value: 存放旧的timeout值,一般指定为NULL 

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

四、 给信号 注册 自定义函数

        信号处理方式:执行默认动作,终止进程、忽略信号、执行自定义动作。 

        注意:不能更改信号的处理方式:SIGKILL 和 SIGSTOP,因为它们向用户提供了一种使 进程终止的可靠方法

        捕捉信号并且信号信号的处理方式有两个函数,signalsigaction

 1、signal函数 

#include<signal.h>

typedef void(*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);  

功能: 注册信号处理函数(不可用于 SIGKILL、SIGSTOP 信号),即确定收到信号后处理函数 的入口地址。此函数不会阻塞。

参数:

        signum:信号的编号,这里可以填数字编号,也可以填信号的宏定义,可以通过命令 kill - l("l" 为字母)进行相应查看。

        handler : 取值有 3 种情况:

                SIG_IGN忽略该信号

                SIG_DFL:执行系统默认动作

                信号处理函数名:自定义信号处理函数,如:func

                        回调函数的定义如下:

                        void func(int signo)

                         {

                                // signo 为触发的信号,为 signal() 第一个参数的值

                        }

        返回值: 成功:第一次返回 NULL,下一次返回此信号上一次注册的信号处理函数的地址。如果需要使用此返回值,必须在前面先声明此函数指针的类型。 失败:返回 SIG_ERR

         该函数由ANSI定义,由于历史原困在不同版本的Unix和不同版本的 Linux中可能有不同的行为。因此应该尽量避免使用它,取而代之使用sigaction函数。

2、 sigaction函数

#include<signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);  

 功能: 检查或修改指定信号的设置(或同时执行这两种操作)。

参数:

        signum:要操作的信号。

        act: 要设置的对信号的新处理方式(传入参数)。

        oldact:对原来信号的处理方式(传出参数)。

        如果 act 指针非空,则要改变指定信号的处理方式(设置),如果 oldact 指针非空,则 系统将此前指定信号的处理方式存入 oldact。

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

        struct sigaction结构体:

        struct sigaction {

                void(*sa_handler)(int); //旧的信号处理函数指针

                void(*sa_sigaction)(int, siginfo_t *, void *); //新的信号处理函数指针

                sigset_t sa_mask; //信号阻塞集,延时一些信号处理。

                int sa_flags; //信号处理的方式

                void(*sa_restorer)(void); //已弃用

                };

        1) sa_handler、sa_sigaction:信号处理函数指针,和 signal() 里的函数指针用法一样,应 根据情况给sa_sigaction、sa_handler 两者之一赋值,其取值如下:

                a) SIGIGN:忽略该信号

                b) SIGDFL:执行系统默认动作

                c) 处理函数名:自定义信号处理函数

        信号处理函数: void(*sa_sigaction)(int signum, siginfo_t *info, void *context);

        参数说明:

                signum:信号的编号。

                info:记录信号发送进程信息的结构体。

                context:可以赋给指向 ucontext_t 类型的一个对象的指针,以引用在传递信号时``被中断的接收进程或线程的上下文.

        2) sa_mask:信号阻塞集,在信号处理函数执行过程中,临时屏蔽阻塞指定的信号。

        3) sa_flags:用于指定信号处理的行为,通常设置为0,表使用默认属性。它可以是以下值 的“按位或”组合:

                Ø SA_RESTART:使被信号打断的系统调用自动重新发起(已经废弃)

                Ø SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信 号。

                Ø SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子 进程如果退出也不会成为僵尸进程。

                Ø SA_NODEFER:让信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信 号。

                Ø SA_RESETHAND:信号处理之后重新设置为默认的处理方式。

                Ø SA_SIGINFO:使用 sasigaction 成员而不是 sahandler 作为信号处理函数。

五、集合操作 

 1、信号集合的概述

        在PCB中有两个非常重要的信号集。一个称之为“阻塞信号集”,另一个称之为“未决信号集”。 这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对其进行位操作。而需自定义另外一个集合,借助信号集操作函数来对PCB中的这两个信号集进行修改 。

 2、自定义信号集函数

#include<signal.h>

int sigemptyset(sigset_t *set); //将set集合置空

int sigfillset(sigset_t *set); //将所有信号加入set集合

int sigaddset(sigset_t *set, int signo); //将signo信号加入到set集合

int sigdelset(sigset_t *set, int signo); //从set集合中移除signo信号

int sigismember(const sigset_t *set, int signo); //判断信号是否存在  

sigset_t(数据类型) set(set即一个自定义信号集) 

        信号阻塞集也称信号屏蔽集、信号掩码。每个进程都有一个阻塞集,创建子进程时子进程将继承父进程的阻塞集。 所谓阻塞并不是禁止传送信号, 而是暂缓信号的传送。 

3、sigprocmask 阻塞集操作函数

#include<signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);  

功能: 检查或修改信号阻塞集,根据 how 指定的方法对进程的阻塞集合进行修改,新的信号阻塞集由 set 指定,而原先的信号阻塞集合由 oldset 保存。

参数:

how : 信号阻塞集合的修改方法,有 3 种情况:

  • SIG_BLOCK:向信号阻塞集合中添加 set 信号集,新的信号掩码是set和旧信号掩码 的并集。 
  • SIG_UNBLOCK:从信号阻塞集合中删除 set 信号集,从当前信号掩码中去除 set 中 的信号。相当于 mask = mask & ~ set。
  • SIG_SETMASK:将信号阻塞集合设为 set 信号集,相当于原来信号阻塞集的内容清空,然后按照 set 中的信号重新设置信号阻塞集。相当于mask = set。

set : 要操作的信号集地址。 若 set 为 NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到 oldset 中。

oldset : 保存原先信号阻塞集地址

返回值: 成功:0, 失败:-1,失败时错误代码只可能是 EINVAL,表示参数 how 不合法

4、sigpending未决信号集函数

#include<signal.h>

int sigpending(sigset_t *set);

功能:读取当前进程的未决信号集

参数: set:未决信号集

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

六、进程间通信方式(IPC)

进程间通信方式有7种通信方式:

同一主机的进程通信:无名管道、有名管道(命令管道)、消息队列、mmap、共享内 存、信号 不同主机的进程通信:socket(网络通信) 

  1. 无名管道:血缘关系、半双工、一对一、先进先出、无格式、数据读取后就丢弃(内存 中)
  2. 有名管道:有/无血缘、半双工、一对一、先进先出、无格式、数据读取后就丢弃(内存抽象成文件名)
  3. 消息队列:有/无血缘、多对多、按消息类型收取、同类型先进先出、有格式、数据读取后就丢弃 (内存中)
  4. mmap(存储/磁盘映射):多对多、无格式、数据读取后存在、写入覆盖以前数据(磁盘中)
  5. 共享内存:多对多、无格式、数据读取后存在、写入覆盖以前数据(物理内存)
  6. 信号:简单 不能携带大量信息 满足某个特设条件才发送
  7. socket:不同主机间的进程通信(网络通信 

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

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

相关文章

RHEL8部署baichuan2环境

前置 1、安装NVIDIA驱动 https://www.nvidia.cn/Download/index.aspx?langcn 阿里云 Alibaba Cloud Linux 3.2104 LTS 64位&#xff0c;需要选择RHEL8&#xff0c;如果没有RHEL8&#xff0c;则选最下面那个选择所有操作系统 点击搜索&#xff0c;下载这里有安装步骤&#x…

Datawhale【Sora原理与技术实战】| 学习笔记3

目录 一. 训练 Sora 模型二. 数据预处理三. 视频 VQVAE四. Diffusion Transformer 一. 训练 Sora 模型 Open-Sora 在下图中总结了 Sora 可能使用的训练流程&#xff1a; 链路: 二. 数据预处理 目前主流 LLM 框架缺乏针对 video 数据 统一便捷的管理和处理能力&#xff0c;…

天水麻辣烫:麻辣鲜香,地城风情尽在其中

天水麻辣烫&#xff0c;这道源自甘肃天水的地道美食&#xff0c;早已成为当地饮食文化中不可或缺的一部分。追溯其源头&#xff0c;它脱胎于上世纪80、90年代的麻辣粉&#xff0c;那时的麻辣粉&#xff0c;以土豆粉和土豆片为主&#xff0c;辅以香辣的油泼辣子&#xff0c;简单…

【C++ 】stack 和 queue

1. 标准库中的stack stack 的介绍&#xff1a; 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行 元素的插入与提取操作 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其…

月结常见工单异常情况处理

1. 上月已经结算的工单&#xff0c;本月打开投料或者报工&#xff0c;或者增加产出 或者撤销报工修正报工 如果针对结算的订单&#xff0c;打开重新投料。 月末对工单重新结算&#xff0c;转出差异 KKS2单个处理&#xff08;KKS1集中处理&#xff09; 差异计算 KO88单个结算…

ThreadLocal基本原理

ThreadLocal基本原理 一、定义 ThreadLocal是java中所提供的线程本地存储机制&#xff0c;可以利用改机制将数据缓存在线程内部&#xff0c;该线程可以在任意时刻、任意方法中获取数据 二、底层原理 ThreadLocal底层是通过ThreadLocalMap来实现的&#xff0c;每个Thread对象中…

短剧APP系统开发:打造全新的掌上剧场体验

随着移动互联网的普及和人们娱乐方式的多样化&#xff0c;短剧已经成为现代人生活中不可或缺的一部分。为了满足用户对高质量、便捷观看短剧的需求&#xff0c;我们致力于开发一款功能全面、操作简便的短剧APP系统&#xff0c;为用户带来前所未有的掌上剧场体验。 一、系统开发…

AJAX 04 回调函数地狱和 Promise 链式调用、async 和 await、事件循环

AJAX 学习 AJAX 04 进阶01 同步代码和异步代码02 回调函数地狱和 Promise 链式调用(1) 回调函数地狱(2) Promise 链式调用(3) Promise 链式应用 03 async 和 await(1) async 和 await 使用(2) async函数和await捕获错误 04 事件循环-EventLoop(1) 事件循环(2) 事件循环练习(3) …

FREERTOS简介、移植和系统配置(基于STM32F103)

本文基础内容参考的是正点原子的FREERTOS课程。 这是基于HAL库的 正点原子手把手教你学FreeRTOS实时系统 这是基于标准库的 正点原子FreeRTOS手把手教学-基于STM32 基础知识&#xff0c;直接参考正点原子《FreeRTOS开发指南V1.1》基于标准库的&#xff0c;此处不再赘述。 本文…

SwiftUI的context Menu

SwiftUI的 context Menu 现在来演示一下如何使用 SwiftUI 的 Context Menu 。 代码&#xff1a; import SwiftUIstruct ContextMenuBootCamp: View {State var bgColor: Color .purplevar body: some View {VStack(alignment: .leading, spacing: 10.0) {Image(systemName: …

【LeetCode】升级打怪之路 Day 21:二叉树的最近公共祖先(LCA)问题

今日题目&#xff1a; 236. 二叉树的最近公共祖先1644. 二叉树的最近公共祖先 II235. 二叉搜索树的最近公共祖先 目录 LCA 问题LC 236. 二叉树的最近公共祖先 【classic】LC 1644. 二叉树的最近公共祖先 II 【稍有难度】LC 235. 二叉搜索树的最近公共祖先 ⭐⭐⭐ 今天做了几道有…

电源常用电路—驱动电路详解

数字电源控制核心对输入输出参数进行采集后&#xff0c;利用控制算法进行分析从而产生PWM控制信号&#xff0c;PWM信号将经过驱动电路的进行功率放大和隔离&#xff0c;随后接入功率开关器件从而完成电源的输出控制。本篇将主要针对电源的驱动电路进行讲解。 一、驱动电路概述…

高效Go编程: encoding/csv标准库深度解析

高效Go编程: encoding/csv标准库深度解析 引言了解encoding/csv库CSV文件的基本结构encoding/csv库的核心功能应用场景 读取CSV文件基本步骤代码示例处理不同的分隔符错误处理 处理CSV数据数据解析代码示例处理不规则数据代码示例 写入CSV文件基本步骤代码示例自定义设置错误处…

C语言——详解字符函数和字符串函数(一)

Hi,铁子们好呀&#xff01;今天博主来给大家更一篇C语言的字符函数和字符串函数~ 具体讲的内容如下&#xff1a; 文章目录 &#x1f386;1.字符分类函数&#x1f4af;&#x1f4af;⏩1.1 什么是字符分类函数的&#xff1f;&#x1f4af;&#x1f4af;⏩1.2 字符函数的类型有哪…

DXP软件界面显示“No Hard Devices”【简单的操作问题】加【软件下载】

目录 一&#xff0c;DXP软件界面显示“No Hard Devices” 二&#xff0c;软件下载的百度网盘资源 一&#xff0c;DXP软件界面显示“No Hard Devices” Protel DXP是2004是澳大利亚Altium公司于2002年推出的一款电子设计自动化软件。它的主要功能包括&#xff1a;原理图编辑、印…

北斗卫星推动数智油田建设

北斗卫星推动数智油田建设 中国石油大港油田采油三厂深入推动北斗智能终端在智能巡检、安全监督、油井导航、坐标测绘等多场景应用&#xff0c;实现了人工查井向智能巡检的变革。截至2月下旬&#xff0c;场景覆盖率达100%&#xff0c;高效助推大港南部“双高”老区数智油田建设…

修改vscode的相对路径计算逻辑

vscode的相对路径计算逻辑是&#xff0c;"./"表示当前项目的文件夹&#xff0c;而不是当前文件所在的文件夹 做出如下修改&#xff1a; File-->Preferences-->settings 搜索Execute in File Dir , 然后取消勾选

TikTok新手如何起号?环境因素与内容创新技巧

相信很多刚入行的TikTok玩家都遇到过一个难题&#xff0c;那就是账号权重低&#xff0c;播放量在个位数徘徊&#xff0c;其实都是因为还没起号&#xff01;那么具体如何起号呢&#xff1f;下面小编也给大家分享一下技巧。 一、如何起号 1、明确注册 TikTok 账号的目的 无论是…

Linux 管道

目录 一、认识管道 二、匿名管道 pipe函数 用法&#xff1a; pipefd&#xff1a; 匿名管道通信&#xff1a; 三、命名管道 概念&#xff1a; 创建&#xff1a; 特性&#xff1a; 用途&#xff1a; 四、命名管道和匿名管道的区别 命名&#xff1a; 持久性&#xff1a;…

MySQL:概念简章

1.SQL通用语法 SQL单行、多行书写&#xff0c;以分号结尾SQL可以以空格有缩进增加代码可读性SQL语句不区分大小写 2.SQL语句分类 2.1 DDL&#xff08;数据定义语言&#xff09; 用于数据库、数据表、字段的定义的语言 create by 表名 &#xff08;表里有什么字段&#xff09;…