《Linux C编程实战》笔记:信号处理函数的返回

信号处理函数可以正常返回,也可以调用其他函数返回到程序的主函数中,而不是从处理程序返回。

setjmp/longjmp

使用longjmp可以跳转到setjmp设置的位置

这两个函数原型如下

#include<setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env,int val);

参数env是一个特殊类型jmp_buf 的变量。这一数据类型是某种形式的数组,其中存放的是在调用longjmp时能用来恢复栈状态的所有信息。一般来说env是个全局变量,因为需从另一个函数中引用它。我们可以在希望返回的位置使用setjmp,直接调用setjmp时返回0;当从longjmp返回时,setjmp的返回值是longjmp的第2个参数的值,可以利用这一点使多个longjmp返回到一个setjmp处。

示例程序1

演示这两个函数的用法

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<setjmp.h>
jmp_buf env;//保存待跳转位置的栈信息
void handler_sigrtmin(int signo){printf("recv SIGRTMIN\n");longjmp(env,1);//返回到env处,第二个参数是1
}
void handler_sigrtminplus1(int signo){printf("recv sigrtmin+1\n");longjmp(env,2);
}
int main(){printf("pid:%d\n",getpid());//打印出本进程的id,方便之后使用//设置返回点switch (setjmp(env)){case 0:break;case 1:printf("return from SIGRTMIN\n");break;case 2:printf("return from SIGRTMIN+1\n");break;default:break;}signal(SIGRTMIN,handler_sigrtmin);signal(SIGRTMIN+1,handler_sigrtminplus1);while (1);return 0;
}

程序在main函数内调用setjmp设置了返回点。信号处理函数内部打印出提示信息后没有正常返回,而是调用longjmp直接跨函数跳转,返回到setjmp处。

执行程序时,在一个终端执行本程序,在另一个终端用kill命令发送信号

首先打印出pid,之后我们打开另一个终端,往程序发信号

再回去看看

结果符合预期。

但是就没有问题了吗,我们继续用kill发送同样的信号

我们用kill连续发三个同样的信号

但是程序里只响应了一次

这是为什么呢?正如我们在《Linux C编程实战》笔记:信号的捕捉和处理-CSDN博客所介绍的,信号处理时会自动阻塞正在被处理的信号,在信号处理函数返回时把进程的信号屏蔽字恢复,即解除对当前信号的阻塞。示例程序没有让信号处理函数正常返回,而是使用longjmp直接跳转,所以进程的信号屏蔽字在第一次收到信号后, 就把信号设置为阻塞并且再也没有恢复,因而再也触发不了信号处理函数了,除非手动将进程对信号的屏蔽去除。如果既想使用跨函数跳转直接返回,又想避免每次都手动清除信号屏蔽的麻烦,就要使用下面的函数了。

sigsetjmp/siglongjmp

为了解决信号被屏蔽的问题,可以用下面两个函数来解决问题

#include<setjmp.h>
int sigsetjmp(sigjmp_buf env,int savesigs);
void siglongjmp(sigjmp_buf env,int val);

这两个函数和之前的函数的唯一区别就是sigsetjmp多了一个参数savesigs,如果savesigs非0,则sigsetjmp在env中保存进程的当前信号屏蔽字,在调用siglongjmp时会从其中恢复保存的信号屏蔽字。

示例程序2

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<setjmp.h>
#define ENV_UNSAVE 0
#define ENV_SAVED 1
int flag_saveenv=ENV_UNSAVE;
sigjmp_buf env;
void handler_sigrtmin(int signo){if(flag_saveenv==ENV_UNSAVE)return;printf("recv SIGRTMIN\n");sleep(10);printf("in handler_sigrtmin,after sleep");siglongjmp(env,1);
}
int main(){printf("pid:%d\n",getpid());switch (sigsetjmp(env,1))//第二个参数只要不是0就可以{case 0:printf("return 0\n");flag_saveenv=ENV_SAVED;break;case 1:printf("return from SIGRTMIN\n");break;default:printf("return else\n");break;}signal(SIGRTMIN,handler_sigrtmin);while (1);return 0;
}

本程序的信号处理函数先检查flag_saveenv的值是否为ENV_UNSAVE,如果是,则直接返回,因为此时程序还没来得及保存返回点的栈状态信息。在sigsetjmp 之后才将flag_ saveenv设置为ENV_ SAVED。如果不这样处理,那么当信号发生在调用sigsetjmp之前时,信号处理函数将返回到未知地点或程序崩溃(感兴趣的读者可以在sigsetjmp前面加上sleep (20),可以观察到程序崩溃)。使用siglongjmp从信号处理程序返回时都应该这样处理。

(这是书上所说的,我感觉书上说的情况可能代码是signal放在sigsetjmp之前,这样可能没执行sigsetjmp就有信号发生,示例的代码是先执行sigsetjmp再绑定的信号处理函数,不会发生上面所说的情况)

执行流程如图

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

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

相关文章

QQ数据包解密

Windows版qq数据包格式&#xff1a; android版qq数据包格式&#xff1a; 密钥&#xff1a;16个0 算法&#xff1a;tea_crypt算法 pc版qq 0825数据包解密源码&#xff1a; #include "qq.h" #include "qqcrypt.h" #include <WinSock2.h> #include…

构建库函数雏形(以GPIO为例)

构建库函数雏形 进行外设结构体定义构建置位和复位函数进行库函数的自定义 step I&#xff1a; \textbf{step I&#xff1a;} step I&#xff1a; 对端口进行输出数据类型枚举 step II&#xff1a; \textbf{step II&#xff1a;} step II&#xff1a;对端口进行结构化描述 step…

线性代数的学习和整理23:用EXCEL和python 计算向量/矩阵的:内积/点积,外积/叉积

目录 1 乘法 1.1 标量乘法(中小学乘法) 1.1.1 乘法的定义 1.1.2 乘法符合的规律 1.2 向量乘法 1.2.1 向量&#xff1a;有方向和大小的对象 1.2.2 向量的标量乘法 1.2.3 常见的向量乘法及结果 1.2.4 向量的其他乘法及结果 1.2.5 向量的模长&#xff08;长度&#xff0…

第三篇【传奇开心果系列】Vant开发移动应用:财务管理应用

传奇开心果博文系列 系列博文目录Vant开发移动应用系列博文 博文目录一、项目目标二、编程思路三、初步实现示例代码四、扩展思路五、使用Firebase等后端服务来实现用户认证和数据存储示例代码六、用Vant组件库实现收入和支出分类管理的示例代码七、用Vant组件库实现收入和支出…

Redis经典五大类型源码及底层实现

Redis经典五大类型源码及底层实现分析 1、一些题目 redis的zset底层实现&#xff1f;redis的跳表和压缩列表说一下&#xff0c;解决了哪些问题&#xff0c;时间复杂度和空间复杂度如何&#xff1f;redis的zset使用的是什么数据结构&#xff1f; Redis数据类型的底层数据结构…

《WebKit 技术内幕》之五(1): HTML解释器和DOM 模型

第五章 HTML 解释器和 DOM 模型 1.DOM 模型 1.1 DOM标准 DOM &#xff08;Document Object Model&#xff09;的全称是文档对象模型&#xff0c;它可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。这里的文档可以是 HTML 文档、XML 文档或者 XHTML 文档。D…

python基本数据类型 - 字典集合

引入 在内存中存储的数据可以是不同的数据类型。比如名字可以使用字符串存储&#xff0c;年龄可以使用数字存储&#xff0c;python有6种基本数据类型&#xff0c;用于各种数据的存储&#xff0c;分别是&#xff1a;numbers(数字类型)、string(字符串)、List(列表)、Tuple(元组…

【笔记】Blender4.0建模入门-3物体的基本操作

Blender入门 ——邵发 3.1 物体的移动 演示&#xff1a; 1、选中一个物体 2、选中移动工具 3、移动 - 沿坐标轴移动 - 在坐标平面内移动 - 自由移动&#xff08;不好控制&#xff09; 选中物体&#xff1a;右上的大纲窗口&#xff0c;点击物体名称&#xff0c;物体的轮…

文件操作(上)

目录 文件的必要性&#xff1a; 文件分类&#xff1a; 程序文件&#xff1a; 数据文件&#xff1a; 文件的打开与关闭&#xff1a; fopen函数分析: ​编辑 FILE*: char*filename: char*mode: fclose函数&#xff1a; 应用&#xff1a; 文件编译 Fgetc Fputc 应用…

HNU-数据挖掘-作业1

数据挖掘课程作业作业1 计科210X 甘晴void 202108010XXX 第一题 假设所分析的数据包括属性 age,它在数据元组中的值&#xff08;以递增序&#xff09;为13 ,15 ,16 ,16 ,19 ,20 ,20 ,21 ,22 ,22 ,25 ,25 ,25 ,25 ,30 ,33 ,33 ,35 ,35 ,35 ,35 ,36 ,40 ,45 ,46 ,52,70。 a.…

基于Unity平台开发Vision Pro应用

VisionOS是苹果最新空间计算设备Vision Pro的操作系统。Unity开发人员可以利用现有的3D场景 以及为 visionOS 构建游戏或应用程序的资产。有关 visionOS 的更多信息&#xff0c;请参阅 Apple 的 visionOS 概述。 visionOS提供了几种不同的显示应用程序的模式&#xff1a;Windo…

【网站项目】基于SSM的274办公自动化管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

JVM系列-1.初识JVM

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…

异或运算的骚操作,由浅入深拿捏一类型的题

文章目录 &#x1f680;前言&#x1f680;异或运算的基本用法&#x1f680;一组数中一种数出现了奇数次&#xff0c;其他种数出现了偶数次&#xff0c;找出这个数&#x1f680;一组数中有两种数出现了奇数次&#xff0c;其他种数出现了偶数次&#xff0c;求这两个数✈️得到一个…

Spring Boot3.2.2整合MyBatis Plus3.5.5

目录 1.前置条件 2.导坐标 3.配置数据源 4.配置mapper扫描路径 5.MyBatis Plus代码生成器整合 1.导坐标 2.编写代码生成逻辑 1.前置条件 已经初始化好一个spring boot项目且版本为3X&#xff0c;项目可正常启动 2.导坐标 <dependency><groupId>com.baomid…

弹性调度助力企业灵活应对业务变化,高效管理云上资源

作者&#xff1a;吴昆 什么是弹性调度 云计算时代&#xff0c;企业可以通过云平台获得大量计算资源&#xff0c;并根据业务发展和流量需求的实时变化&#xff0c;灵活调整使用的资源类型与资源量。阿里云提供了多种弹性资源&#xff0c;如云服务器 ECS 和弹性容器实例 ECI&am…

基于 Spring Boot+MySQL实现的在线考试系统源码+数据库,基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统

1. 部署相关 1.1. 介绍 一个 JAVA 实现的在线考试系统,主要实现一套基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统&#xff08;没有主观题&#xff09; 1.2. 系统架构 后端技术栈基于 Spring Boot数据库MySQLORMMyBatis & MyBatis-plus缓存Redis、guava的L…

【Java网络编程02】套接字编程

【Java网络编程02】套接字编程 1. Socket套接字 概念&#xff1a;Socket套接字&#xff0c;就是系统提供用于实现网络通信的技术&#xff0c;是基于TCP/IP协议的网络通信基本操作单元。基于Socket套接字的网络程序开发就是网络编程。 分类&#xff1a; 我们可以把Socket套接字…

docker 部署 sentinel

docker 部署 sentinel 环境安装 拉取镜像 目前稳定的版本是1.8.0 docker pull bladex/sentinel-dashboard:1.8.0启动服务 docker run --name sentinel -p 8858:8858 -td bladex/sentinel-dashboard:1.8.0登录 登录的时候账号和密码都是sentinel

算法训练营Day45

#Java #动态规划 Feeling and experiences&#xff1a; 最长公共子序列&#xff1a;力扣题目链接 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新…