Linux系统编程系列之线程的信号处理
一、为什么要有线程的信号处理
由于多线程程序中线程的执行状态是并发的,因此当一个进程收到一个信号时,那么究竟由进程中的哪条线程响应这个信号就是不确定的,只能取决于哪条线程刚好在信号达到的瞬间被调度,这种不确定性在程序逻辑中一般是不能接受的。
二、解决办法
1、在多线程进程中选定某条线程去响应信号
2、其余线程对该信号进行屏蔽
三、相关函数API接口
1、发送信号给指定线程
// 在进程内部,只允许在线程之间进行发送 int pthread_kill(pthread_t thread, int sig);// 接口说明返回值:成功返回0,失败返回错误码参数thread:接收信号的线程号参数sig:待发送的信号// 在进程之间进行的信号发送 int kill(pid_t pid, int sig);// 接口说明返回值:成功返回0,失败返回-1参数pid:接受信号的进程号参数sig:待发送的信号
2、发送带参数的信号给指定线程
// 发送带参数的信号给指定线程 // 线程间 int pthread_sigqueue(pthread_t thread, int sig,const union sigval value);// 接口说明返回值:成功返回0,失败返回-1参数thread:待接收信号的线程号参数sig:待发送的信号参数value:额外携带的参数// 进程间int sigqueue(pid_t pid, int sig, const union sigval value);// 接口说明返回值:成功返回0,失败返回-1参数pid:待接收信号的进程号参数sig:待发送的信号参数value:额外携带的参数
3、屏蔽指定信号
// 屏蔽指定信号 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);// 接口说明返回值:成功返回0,失败返回-1// 参数解析: 1、how:操作命令字,比如阻塞、解除阻塞等SIG_BLOCK:阻塞set中的信号(原有正在阻塞的信号保持阻塞)SIG_SETMASK:阻塞set中的信号(原有正在阻塞的信号自动解除)SIG_UNBLOCK:解除set中的信号2、set:当前要操作的信号集 3、oldset:若为非空,则将原有阻塞信号集保留到该oldset中 注意:该函数的操作参数不是单个信号,而是信号集。// 信号集操作函数组 int sigemptypset(sigset_t *set); // 清空信号集set int sigfillset(sigset_t *set); // 将所有信号加入信号集set中 int sigaddset(sigset_t *set, int signum); // 将信号signum添加到信号集set中 int sigdelset(sigset_t *set, int signum); // 将信号signum从信号集set中剔除 int sigsimember(const sigset_t *set, int signum); // 测试信号signum是否在信号集set中
四、案例
1、使用线程结合信号的方式完成数据的接收和发送,要求一条线程发送数据同时发送信号指定某条线程接收数据,另外有多余线程做伪任务。
// 多线程信号处理的案例#include <stdio.h> #include <pthread.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <signal.h>char data[100]; pthread_t tid1, tid2, tid3;// 信号响应函数 void recv_handler(int sig) {printf("\nmy tid is %ld\n", pthread_self());printf("read data: %s\b", data);memset(data, 0, sizeof(data)); }// 线程1的例程函数 void *routine1(void *arg) {printf("I am recv_routine, my tid = %ld\n", tid1);// 设置线程分离 pthread_detach(pthread_self()); while(1){printf("please input data:\n");fgets(data, sizeof(data), stdin);pthread_kill(tid2, 34); // 给线程2发送信号printf("send data success\n");} }// 线程2的例程函数,用来接收数据 void *routine2(void *arg) {// 注册信号响应函数signal(34, recv_handler);printf("I am routine2, my tid = %ld\n", tid2);// 设置线程分离 pthread_detach(pthread_self());while(1){pause();} }// 线程3的例程函数 void *routine3(void *arg) {printf("I am routine3, my tid = %ld\n", tid3);// 设置线程分离 pthread_detach(pthread_self());while(1){pause();} }int main(int argc, char *argv[]) {// 创建线程1,用来发送和接收数据errno = pthread_create(&tid1, NULL, routine1, NULL);if(errno == 0){printf("pthread create routine1 success, tid = %ld\n", tid1);}else{perror("pthread create routine1 fail\n");}// 创建线程2,用来做多余线程errno = pthread_create(&tid2, NULL, routine2, NULL);if(errno == 0){printf("pthread create routine2 success, tid = %ld\n", tid2);}else{perror("pthread create routine2 fail\n");}// 创建线程3,用来做多余线程errno = pthread_create(&tid3, NULL, routine3, NULL);if(errno == 0){printf("pthread create routine3 success, tid = %ld\n", tid3);}else{perror("pthread create routine3 fail\n");}// 一定要加这个,否则主函数直接退出,相当于进程退出,所有线程也退出// 或者加上while(1)等让主函数不退出pthread_exit(0);return 0; }
2、使用线程结合信号的方式完成数据的接收和发送,要求一条线程完成数据的发送和接收,另外两个线程屏蔽信号,做伪任务。
// 多线程信号处理的案例#include <stdio.h> #include <pthread.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <signal.h>char data[100]; sigset_t sigs_set; // 信号集 pid_t pid; pthread_t tid1, tid2, tid3;// 信号响应函数 void recv_handler(int sig) {printf("\nmy tid is %ld\n", pthread_self());printf("read data: %s\b", data);memset(data, 0, sizeof(data)); }// 线程1的例程函数 void *routine1(void *arg) {printf("I am routine1, my tid = %ld\n", tid1);// 设置线程分离 pthread_detach(pthread_self()); while(1){printf("please input data:\n");fgets(data, sizeof(data), stdin);printf("send data success\n");kill(pid, 34); // 给进程(所有线程)发送信号} }// 线程2的例程函数,用来接收数据 void *routine2(void *arg) {printf("I am routine2, my tid = %ld\n", tid2);// 屏蔽(阻塞)信号集中的信号sigprocmask(SIG_BLOCK, &sigs_set, NULL);// 设置线程分离 pthread_detach(pthread_self());while(1){pause();} }// 线程3的例程函数 void *routine3(void *arg) {printf("I am routine3, my tid = %ld\n", tid3);// 设置线程分离 pthread_detach(pthread_self());// 屏蔽(阻塞)信号集中的信号sigprocmask(SIG_BLOCK, &sigs_set, NULL);while(1){pause();} }int main(int argc, char *argv[]) {// 注册信号响应函数signal(34, recv_handler);sigemptyset(&sigs_set); // 清空信号集sigaddset(&sigs_set, 34); // 把34信号加到信号集中pid = getpid(); // 获取进程号// 创建线程1,用来发送和接收数据errno = pthread_create(&tid1, NULL, routine1, NULL);if(errno == 0){printf("pthread create routine1 success, tid = %ld\n", tid1);}else{perror("pthread create routine1 fail\n");}// 创建线程2,用来做多余线程errno = pthread_create(&tid2, NULL, routine2, NULL);if(errno == 0){printf("pthread create routine2 success, tid = %ld\n", tid2);}else{perror("pthread create routine2 fail\n");}// 创建线程3,用来做多余线程errno = pthread_create(&tid3, NULL, routine3, NULL);if(errno == 0){printf("pthread create routine3 success, tid = %ld\n", tid3);}else{perror("pthread create routine3 fail\n");}// 一定要加这个,否则主函数直接退出,相当于进程退出,所有线程也退出// 或者加上while(1)等让主函数不退出pthread_exit(0);return 0; }
五、总结
多线程进程中的信号处理可以采用选定某一条线程来接收信号,其余线程屏蔽该信号的做法,可以结合案例加深对多线程中信号的处理。
相关文章:
Linux系统编程系列之线程的信号处理
一、为什么要有线程的信号处理 由于多线程程序中线程的执行状态是并发的,因此当一个进程收到一个信号时,那么究竟由进程中的哪条线程响应这个信号就是不确定的,只能取决于哪条线程刚好在信号达到的瞬间被调度,这种不确定性在程序逻…...
【C语言】青蛙跳台阶 —— 详解
一、问题描述 跳台阶_牛客题霸_牛客网 (nowcoder.com) LCR 127. 跳跃训练 - 力扣(LeetCode) 二、解题思路 1、当 n 1 时,一共只有一级台阶,那么显然青蛙这时就只有一种跳法 2、当 n 2 时,一共有两级台阶ÿ…...
Java - 基本数据类型和封装类型
基本类型有默认值,而包装类型初始为null。然后再根据这两个特性进行分业务使用,在阿里巴巴的规范里所有的POJO类必须使用包装类型,而在本地变量推荐使用基本类型。 Java语言提供了八种基本类型。六种数字类型(四个整数型ÿ…...
day-63 代码随想录算法训练营(19) 图论 part 02
1020.飞地的数量 分析:求不跟边界接壤的陆地的数量 思路一:深度优先遍历 先从四个侧边找陆地,然后进行深度优先遍历,把所有接壤的陆地(1)全部转换成海洋(0) 深度优先遍历…...
SpringBoot的全局异常拦截
在 Spring Boot 中,可以通过使用 ControllerAdvice 注解和 ExceptionHandler 注解来实现全局异常拦截。 RestControllerAdvice RestControllerAdvice 是 Spring Framework 提供的注解,用于定义全局异常处理类,并且结合 ExceptionHandler 注…...
『力扣每日一题11』:转换成小写字母
一、题目 给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。 示例 1: 输入:s "Hello" 输出:"hello"示例 2: 输入:s "here" 输…...
复习Day07:链表part03:21. 合并两个有序链表、2. 两数相加
之前的blog链接:https://blog.csdn.net/weixin_43303286/article/details/131700482?spm1001.2014.3001.5501 我用的方法是在leetcode再过一遍例题,明显会的就复制粘贴,之前没写出来就重写,然后从拓展题目中找题目来写。辅以Lab…...
Ubuntu中启动HDFS后没有NameNode解决办法
关闭进程: stop-dfs.sh 格式化: hadoop namenode -format 出现报错信息: 23/10/03 22:27:04 WARN fs.FileUtil: Failed to delete file or dir [/usr/data/hadoop/tmp/dfs/name/current/fsimage_0000000000000000000.md5]: it still exi…...
AWS-Lambda之导入自定义包-pip包
参考文档: https://repost.aws/zh-Hans/knowledge-center/lambda-import-module-error-python https://blog.csdn.net/fxtxz2/article/details/112035627 简单来说,以 " alibabacloud_dyvmsapi20170525 " 包为例 ## 创建临时目录 mkdir /tmp cd ./tmp …...
MAC 如何解决GitHub下载速度慢的问题
说在前面 解决github下载速度慢的方法很多,本文主要介绍通过Git镜像的方式解决下载慢的问题。 主要步骤有:1、找到gitconfig文件, 2、通过git命令查看当前生效的config 配置 3、使用git config命令编辑并添加国内镜像源 1、gitconfig 文件在…...
Redis与分布式-哨兵模式
接上文 Redis与分布式-主从复制 1.哨兵模式 启动一个哨兵,只需要修改配置文件即可, sentinel monitor lbwnb 1247.0.0.1 6001 1先将所有服务关闭,然后修改配置文件,redis Master,redis Slave,redis Slave…...
创建型设计模式 原型模式 建造者模式 创建者模式对比
创建型设计模式 单例 工厂模式 看这一篇就够了_软工菜鸡的博客-CSDN博客 4.3 原型模式 4.3.1 概述 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。 4.3.2 结构 原型模式包含如下角色: 抽象原型类:规定了…...
HTML详细基础(二)文件路径
目录 一.相对路径 二.绝对路径 三.超链接标签 四.锚点链接 首先,扩展一些HTML执行的原理: htmL(hypertext markup Language) 是一种规范(或者说是一种标准),它通过标记符(tag)来标记要显示…...
大数据-玩转数据-Flink 海量数据实时去重
一、海量数据实时去重说明 借助redis的Set,需要频繁连接Redis,如果数据量过大, 对redis的内存也是一种压力;使用Flink的MapState,如果数据量过大, 状态后端最好选择 RocksDBStateBackend; 使用布隆过滤器,…...
1.在vsCode上创建Hello,World
(1).编译器的安装配置 使用vsCode进行编写c语言,首先需要安装gcc编译器,可以自己去寻找资料或者gcc官网进行下载. 下载好后,将文件夹放入到自己指定的目录后,配置系统环境变量,将path指向编译器的bin目录 进入bin目录打开cmd,输入gcc -v,然后就会成功输出信息. (2).vsCode配…...
XrayGLM - 医学大模型
文章目录 关于 XrayGLM研究背景VisualGLM-6B 关于 XrayGLM XrayGLM: 首个会看胸部X光片的中文多模态医学大模型 | The first Chinese Medical Multimodal Model that Chest Radiographs Summarization. 基于VisualGLM-6B 微调 github : https://github.com/WangRongsheng/Xra…...
Hive 常见数据倾斜场景及解决方案(Map\Join\Reduce端)
目录 MapReduce流程简述a) Map倾斜b) Join倾斜c) Reduce倾斜 首先回顾一下MapReduce的流程 MapReduce流程简述 输入分片: MapReduce 作业开始时,输入数据被分割成多个分片,每个分片大小一般在 16MB 到 128MB 之间。这些分片会被分配给不同的…...
C++中的四种强制类型转换符详解
前 言 C 既支持 C 风格的类型转换,又有自己风格的类型转换。C 风格的转换格式很简单,但是有不少缺点: 转换太过随意,可以在任意类型之间转换。你可以把一个指向 const 对象的指针转换成指向非 const 对象的指针,把一…...
Windows电脑多开器的优缺点对比
Windows电脑多开器是一种能够让用户同时运行多个应用程序、游戏或者网页的软件工具。它的作用在于让用户能够更加高效地工作、学习或者娱乐。但是,这种软件也存在一些优劣势的对比。 优点: 提升工作效率。多开器可以让用户同时打开多个应用程序或者网页…...
Java笔记六(面向对象:类与对象)
面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据 抽象 三大特征:封装 继承 多态 从认识角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽…...
Git使用【中】
欢迎来到Cefler的博客😁 🕌博客主页:那个传说中的man的主页 🏠个人专栏:题目解析 🌎推荐文章:题目大解析3 目录 👉🏻分支管理分支概念git branch(查看/删除分…...
Greenplum7一键安装
2023年9月底,Greenplum 发布了7.0.0版本,并于2023年10月03日开放了安装部署说明文档,现在快速尝鲜版的docker一键部署方式如下: mkdir /data/gpdb docker run -d --name greenplum -p 15432:5432 -v /data/gpdb:/data inrgihc/g…...
Springboo整合Sentinel
Springboo整合Sentinel 1.启动Sentinel java -jar sentinel-dashboard-1.8.6.jar2.访问localhost:8080到Sentinel管理界面(默认账号和密码都是sentinel) 3.引入依赖(注意版本对应) <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spr…...
python爬取csdn个人首页中的所有封面
#爬取csdn个人首页中的所有封面 import requests import json import reurlhttps://blog.csdn.net/community/home-api/v1/get-business-list? headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safar…...
EasyHttp - 网络请求,如斯优雅
官网 项目地址:Github博客地址:网络请求,如斯优雅 OkHttp 另外对 OkHttp 原理感兴趣的同学推荐你看以下源码分析文章 OkHttp 精讲:拦截器执行原理OkHttp 精讲:RetryAndFollowUpInterceptorOkHttp 精讲:…...
【Java】Stream的基本使用
Stream特点 Stream的一系列操作组成了Stream的流水线, Stream流水线包含: 数据源: 这里的数据源可能是集合/数组, 可能是生成器, 甚至可能是IO通道(Files.lines)零个或多个中间操作: 中间操作会导致流之间的转化, 如filter(Predicate)一个终端操作: 终端操作会产生最终所需要的…...
idea Springboot 高校科研资源共享系统VS开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 springboot 高校科研资源共享系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发), 系统具有完整的源代码和数据…...
机器学习算法基础--K-means应用实战--图像分割
目录 1.项目内容介绍 2.项目关键代码 3.项目效果展示 1.项目内容介绍 本项目是将一张图片进行k-means分类,根据色彩k进行分类,最后比较和原图的效果。 题目还是比较简单的,我们只要通过k-means聚类,一类就是一种色彩得出聚类之…...
CSS学习小结
css的两种使用方式: ①内嵌样式表 ②导入外部样式表(实际开发常用)<link href"...." rel"stylesheet"/> 选择器: ①标签选择器:通过标签种类决定 ②类选择器:class"..…...
数据挖掘实验(一)数据规范化【最小-最大规范化、零-均值规范化、小数定标规范化】
一、数据规范化的原理 数据规范化处理是数据挖掘的一项基础工作。不同的属性变量往往具有不同的取值范围,数值间的差别可能很大,不进行处理可能会影响到数据分析的结果。为了消除指标之间由于取值范围带来的差异,需要进行标准化处理。将数据…...
淘宝领卷网站什么做/现在做百度推广有用吗
1.通过移位删除前导0或后缀0. DATA: str TYPE char10 VALUE 0010000000. SHIFT str LEFT DELETING LEADING 0. SHIFT str RIGHT DELETING TRAILING 0. 2.调用功能模块去除前导0. 如: 功能模块 CONVERSION_EXIT_ALPHA_OUTPUT. 3.通过数值变量转换也可以去除前导0. DATA: …...
遵义市城乡建设局网站/怎样做网站推广
本节课延续上一节课的内容,您将给所有的页面内容添加动画效果。例如选项卡的滑动切换动画,表单的显示和隐藏动画。 添加一个HStack视图,作为页面底部视图的容器。 添加一个文本视图,根据属性的值是登录还是注册,从而显示不同的文字内容。提示用户进行登录,或者进行注册…...
北京 网站建设 知乎/百度指数的各项功能
关于UIWebView不能响应touchesBegan等四个方法的解决案例 做的APP需要在一个UIWebView中随点击位置动态出现button,用touchesBegan等怎么调试都不行,普通的UIView就可以,找了半天终于知道UIWebView不能这样用,那么怎么做呢&#x…...
佛山网站制作平台/泰安网站推广优化
问题描述 ACM 小组接受了计算机组成原理教研室的一项开发任务,要为计算机组成原理课程开发一款实验面板仿真系统,其中有一项数字显示屏的任务分配给了你。数字显示屏是由一组数字显示单元组成的,每个数字显示单元由七个液晶显示管组成&#…...
自己怎么做彩票投注网站/搜索风云榜百度
单例模式的介绍可参考 https://blog.csdn.net/SummerMangoZz/article/details/57080540 https://blog.csdn.net/qq_37520037/article/details/82719190 体会懒汉式的双重检测的好处 public static synchronized Singleton getInstance() { if(uniqueInstancenull) {…...
网站发产品ps怎么做产品图/站长源码
JavaWeb项目中web.xml有关servlet的基本配置:我们注意到,tomcat下的conf中也有一个web.xml文件,没错的,所有的JavaWeb项目中web.xml都继承自服务器下的web.xml。看一下这个web.xml:xmlns:xsi"http://www.w3.org/2…...