Linux之信号集基础
目录
- 前言
- 一、信号集基础API浅析
- 1.1 sigemptyset
- 1.2 sigfillset
- 1.3 sigaddset
- 1.4 sigdelset
- 1.5 signismember
- 1.6 sigprocmask
- 1.7 sigpending
- 1.8 sigwait
- 二、demo演练
- 2.1 sigismember检查信号
- 2.2 主线程pthread_sigmask阻塞后无法捕捉到特定信号
- 2.3 主线程pthread_sigmask阻塞后sigwait()捕捉特定信号
- 2.4 sigfillset添加所有信号、alarm发送信号、ctrl+c退出
- 2.5 示例4进化:添加线程,volatile 从内存读取最新值
- 三、信号集的应用场景
- 四、信号集VS信号量
前言
在 Linux 中,信号集(Signal Set)是一种用于管理和选择信号的机制。信号集可以用来屏蔽、限制或对特定信号进行操作,是信号处理的一个重要组成部分。信号是Linux系统中用于进程间通信的一种机制,它允许一个进程通知另一个进程发生了某种事件。
信号集的作用和用途可以概括如下:
-
信号屏蔽和处理:
信号集允许进程暂时屏蔽(忽略)或处理一组信号。进程可以设置一个信号集,指定在执行某些操作时不希望被某些信号打扰。这对于控制程序的执行流程和避免因信号处理不当导致的竞态条件非常重要。 -
原子操作:
对信号集的操作是原子的,这意味着在设置或清除信号集时,不会有其他信号处理函数同时修改信号集,从而保证了操作的一致性和安全性。 -
信号的阻塞和解除阻塞:
信号集可以用来阻塞一组信号,使得这些信号暂时不会影响进程。当进程准备好处理这些信号时,可以解除阻塞,允许信号被传递给进程。 -
信号的等待和检测:
进程可以使用信号集等待一组信号中的任何一个发生。这允许进程在等待信号时,不必无限期地阻塞,而是可以指定一个信号集,当信号集中的任何一个信号到达时,进程可以被唤醒并处理该信号。 -
提高程序的响应性和稳定性:
通过合理使用信号集,程序可以更好地响应外部事件,同时避免因信号处理不当导致的程序崩溃或数据不一致。 -
系统调用的配合使用:
信号集常与一些系统调用(如sigprocmask、sigsuspend、sigwait等)配合使用,以实现信号的灵活管理。 -
多线程程序中的信号处理:
在多线程程序中,信号集可以用来同步线程间的信号处理,确保信号的适当传递和处理。
一、信号集基础API浅析
1.1 sigemptyset
sigemptyset是初始化set所指向的信号集,让其中所有的信号的对应的比特位清零,表示该信号集不包含任何有效信号。
#include <signal.h>
int sigemptyset(sigset_t *set);
1.2 sigfillset
sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括系统支持的所有信号。
#include <signal.h>
int sigfillset(sigset_t *set);
1.3 sigaddset
sigaddset把某个特定信号加上
#include <signal.h>
int sigaddset(sigset_t *set, int signo);
1.4 sigdelset
sigdelset把某个特定信号去掉
#include <signal.h>
int sigdelset(sigset_t *set, int signo);
1.5 signismember
signismember是为了判断某个信号是否在该信号集中。
#include <signal.h>
int sigismember(const sigset_t *set, int signo);
1.6 sigprocmask
sigprocmask函数用于检查或修改当前进程的信号屏蔽字(signal mask)。信号屏蔽字决定了在屏蔽期间哪些信号会被阻塞,即暂时不会被处理。
语法
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
- int how:操作标志,决定如何修改信号屏蔽字:
- SIG_BLOCK:把 set 指向的信号集中的信号添加到当前信号屏蔽字中。
- SIG_UNBLOCK:从当前信号屏蔽字中移除 set 指向的信号集中的信号。
- SIG_SETMASK:用 set 指向的信号集替换当前信号屏蔽字。
- const sigset_t *set:指向要修改的新信号集的指针。
- sigset_t *oldset:如果不为 NULL,则存储之前的信号屏蔽字
返回值
成功时返回 0。
失败时返回 -1,并设置 errno 以指示错误类型。
1.7 sigpending
用于获取当前进程挂起(未决)的信号集。未决信号是在被阻塞后尚未处理的信号。
#include <signal.h>
int sigpending(sigset_t *set);
1.8 sigwait
用于同步等待信号的到来。它将指定的信号集中的信号之一移出队列并返回其编号。
#include <signal.h>
int sigwait(const sigset_t *set, int *sig);
- const sigset_t *set:指向一个 sigset_t 类型的信号集变量,该信号集指定要等待的信号。
- int *sig:指向一个整数变量,用于存储被捕获的信号编号。
二、demo演练
2.1 sigismember检查信号
#include <stdio.h>
#include <signal.h>int main() {sigset_t set;// 初始化信号集为空if (sigemptyset(&set) == -1) {perror("sigemptyset");return 1;}// 检查信号集是否包含 SIGINTif (sigismember(&set, SIGINT)) {printf("SIGINT is in the set\n");} else {printf("SIGINT is not in the set\n");}return 0;
}
程序运行输出:
SIGINT is not in the set
2.2 主线程pthread_sigmask阻塞后无法捕捉到特定信号
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h> void handler(int s){printf("handler :%d\n" ,s);
}int main(int argc, char**argv)
{signal(SIGINT , handler);sigset_t mask;sigaddset(&mask , SIGINT);pthread_sigmask(SIG_BLOCK,&mask, NULL); //阻塞 SIGINT 信号//用ctrl+\ 终止while(1)pause();return 0;
}
程序运行输出:卡在死循环里。
去掉pthread_sigmask该行后,ctrl+c,SIGINT 信号绑定的程序handler()会正常执行。
2.3 主线程pthread_sigmask阻塞后sigwait()捕捉特定信号
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h>
//gcc 别忘了 -lpthread
void handler(int s){printf("handler :%d\n" ,s);
}int main(int argc, char**argv)
{signal(SIGINT , handler);sigset_t mask;sigaddset(&mask , SIGINT);pthread_sigmask(SIG_BLOCK,&mask, NULL);//用ctrl+\ 终止// while(1)pause();int sig = 0;while(1){if (sigwait(&mask,&sig) != 0 ){perror("sigwait :");continue;}printf(" ! main got signal : %d\n" , sig);}return 0;
}
程序运行输出: 按下ctrl+c,主线程捕捉到信号
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
^C ! main got signal : 2
- sigwait(&mask, &sig) 是一个阻塞操作,它将等待 mask 中的信号到来。尽管主线程设置了对 SIGINT 的屏蔽,但是 sigwait() 允许等待到这个信号。一旦 SIGINT 信号到达,由 Ctrl+C 发送,信号会被添加到信号队列,而 sigwait() 允许线程在收到信号时进行处理。此时不会调用 handler,而是直接将信号交给 sigwait(),并变成返回值。
2.4 sigfillset添加所有信号、alarm发送信号、ctrl+c退出
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h> volatile sig_atomic_t goon = 1;static void * t1(void *arg){sigset_t * mask = (sigset_t *)arg;int sig = 0;while(1){if ( sigwait(mask,&sig) != 0 ){perror(" thread sigwait :");continue;}printf("thread got signal : %d\n" , sig);if(SIGINT == sig){goon = 0;break;}}
}
int main(int argc, char**argv)
{sigset_t mask;sigfillset(&mask); //添加所有信号pthread_sigmask(SIG_BLOCK,&mask, NULL);pthread_t t;pthread_create(&t,0,t1,&mask);int sig = 0;while(goon){alarm(1);sleep(1);}pthread_join(t,0);puts("end");return 0;
}
程序运行输出: 每秒发送对应信号并捕获输出,按下ctrl+c,进程退出
thread got signal : 14
thread got signal : 14
thread got signal : 14
thread got signal : 14
thread got signal : 14
thread got signal : 14
^Cthread got signal : 2
end
2.5 示例4进化:添加线程,volatile 从内存读取最新值
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>volatile sig_atomic_t goon = 1;static void * worker (void *arg){while(goon){printf("worker is running , tid:%ld\n" , pthread_self());sleep(5);}puts("worker is done");
}static void * sig_handler_thread(void *arg){sigset_t * mask = (sigset_t *)arg;int sig = 0;pthread_t tid = pthread_self();while(1){if ( sigwait(mask,&sig) != 0 ){printf("sigwait error : %s\n" , strerror(errno));continue;}printf("thread :%ld got signal : %d\n" , tid,sig);if(SIGINT == sig){goon = 0;break;}}
}int main(int argc, char**argv)
{sigset_t mask;sigfillset(&mask);pthread_sigmask(SIG_BLOCK,&mask, NULL);pthread_t tid1, tid2;pthread_create(&tid1,0,sig_handler_thread,&mask);pthread_create(&tid2,0,worker,NULL);int sig = 0;while(goon){alarm(1);sleep(1);}pthread_join(tid2,0);pthread_join(tid1, NULL);puts("end");return 0;
}
程序运行输出: 与上例类似,自行理解。
worker is running , tid:139906703542016
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
worker is running , tid:139906703542016
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
thread :139906711934720 got signal : 14
worker is running , tid:139906703542016
thread :139906711934720 got signal : 14
^Cthread :139906711934720 got signal : 2
worker is done
end
三、信号集的应用场景
定义: 信号集是一种用于管理多个信号的机制,允许进程或线程一起阻塞或等待多个信号。
常用场景:
-
信号处理:
在需要处理特定信号时,可以使用信号集来定义要阻塞的信号。例如,在多线程程序中,可以屏蔽某些信号,使得信号在关键代码执行期间不会中断,从而避免状态不一致。 -
线程同步:
当多个线程需要等待特定事件(例如消息到达或信号触发)时,可以使用 sigwait() 等函数来实现。这样可以避免在特定上下文中出现信号直接调用处理程序的问题,也能够更好地管理线程状态。 -
状态监控:
信号集可以用来监控系统状态变化。例如,在处理 Unix/Linux 系统的守护进程时,可以使用信号集进行状态更新和管理,从而处理后台服务的停启和运行状态。 -
多线程信号传递:
在多线程应用中,使用信号集可以协调多个线程之间的信号传递,确保在运行时能够安全的捕获并处理来自外部的信号,如终止信号或定时信号。
四、信号集VS信号量
信号量: 主要用于控制对共享资源的访问,帮助管理并发操作,适合资源限制和冲突的问题。
信号集: 主要用于信号的处理和管理,帮助确保在多线程和多进程环境中有效捕获和处理信号。
相关文章:

Linux之信号集基础
目录 前言一、信号集基础API浅析1.1 sigemptyset1.2 sigfillset1.3 sigaddset1.4 sigdelset1.5 signismember1.6 sigprocmask1.7 sigpending1.8 sigwait 二、demo演练2.1 sigismember检查信号2.2 主线程pthread_sigmask阻塞后无法捕捉到特定信号2.3 主线程pthread_sigmask阻塞后…...

unity3d—demo(实现给出图集名字和图片名字生成对应的图片)
目录 实现给出图集名字和图片名字生成对应的图片: 代码示例: dic: 键 是图集名称 值是一个字典 该字典键是图片名称 值是图片,结构如图: 测试代码: 结果: SpriteRenderer 讲解: Resour…...

烟草行业通过Profinet转EthernetIP网关打通数据壁垒
在工业自动化领域,Profinet转Ethernet/IP是两种广泛应用的工业以太网协议。它们各自具有独特的特点和优势,而在实际应用中,经常需要实现这两种协议之间的互通,这时就需要使用到开疆智能Profinet转Ethernet/IP网关KJ-EIP-108。同时…...

2020年国赛高教杯数学建模E题校园供水系统智能管理解题全过程文档及程序
2020年国赛高教杯数学建模 E题 校园供水系统智能管理 原题再现 校园供水系统是校园公用设施的重要组成部分,学校为了保障校园供水系统的正常运行需要投入大量的人力、物力和财力。随着科学技术的发展,校园内已经普遍使用了智能水表,从而可以…...

ip地址显示本地局域网什么意思?ip地址冲突怎么解决
在日常使用网络的过程中,我们可能会遇到IP地址显示“本地局域网”的情况,同时,局域网内IP地址冲突也是一个常见且令人头疼的问题。本文将首先解释IP地址显示本地局域网的含义,随后详细探讨局域网IP地址冲突的解决方法,…...

[软件工程]八.软件演化
8.1什么是软件演化 由于种种不可避免的原因,系统开发完成后的软件需要进行修改来适应变更的需求,我们对软件的修改就叫软件演化。 8.2为什么软件会演化 由于业务的变更或者为了满足用户期待的改变,使得对已有的系统的新需求浮现出来。由于…...

【大数据学习 | 面经】yarn的资源申请和分配的单位-Container
在yarn中,资源的申请和分配是以container为单位进行的,而不是直接以application和task为单位。 每个提交到yarn上的应用程序(application)都有一个对应的ApplicationMaster(AM)。这个AM负责与ResourceMana…...

WiFi受限不再愁,电脑无网络快速修复指南
有时在试图连接WiFi时,会发现网络连接受限,或无法正常访问互联网。这种情况不仅影响了工作效率,还可能错过重要的信息。那么,究竟是什么原因导致了电脑WiFi连接受限呢?又该如何解决这一问题呢?小A今天就来教…...

【组件封装】uniapp vue3 封装一个完整的Tabs(标签页)组件教程,功能由简到杂实现讲解。
文章目录 前言一、简单版Tabs代码实现: 二、下划线带动画的TabsAPI回顾:代码实现: 三、内容区域滑动切换切换动画代码实现:(2)禁用手势滑动切换(3)内容区域换为插槽 四、标签栏可滚动…...

TDesign:Picker 选择器
Picker 选择器 API文档地址 单列选择器用法 /// view onTap:(){TDPicker.showMultiPicker(context,data: [controller.coinList],title: ,rightTextStyle: TextStyle(color: AppColors.ColorMain),onConfirm: (selected) {controller.onTapCoin(selected);Navigator.of(contex…...

【AI赋能心理学论文创作策略】第十二章 AI辅助临床启示撰写指南
AI赋能心理学论文创作策略-系列文章目录 第十二章 AI辅助临床启示撰写指南 文章目录 AI赋能心理学论文创作策略-系列文章目录第十二章 AI辅助临床启示撰写指南 前言基础分析框架第一阶段:核心要素分析第二阶段:应用场景展开 关键环节提示第三阶段&#x…...

Pynsist 打包应用 和 PyWebIO 构建Web 应用
Pynsist:一键打包Python 应用代码为Windows 安装程序。 项目地址: https://github.com/takluyver/pynsist PyWebIO:为Python 开发者提供了一种快速、简洁的方式来创建Web 应用,无需学习前端技术 项目地址:https://g…...

git 使用配置
新拿到机器想配置git 获取代码权限,需要的配置方法 1. git 配置用户名和邮箱 git config --global user.name xxxgit config --global user.email xxemail.com 2. 生成ssh key ssh-keygen -t rsa -C "xxemail.com" 3. 获取ssh key cat ~/.ssh/id_rsa.…...

记一次Mysql的SELECT command denied to user...报错(非权限问题)
java.sql.SQLSyntaxErrorException: SELECT command denied to user ‘user_name’‘1.1.1.1’ for table ‘table_name’。错误信息的字面意思是:表“table_name”拒绝用户“user_name”“1.1.1.1”的SELECT命令 。 比较多的情况是:用户没有查看user表…...

element-plus的el-tree的双向绑定
el-tree改造了下 可选可取消 有默认值 不包含父级id 默认展开 点击节点也可触发选择 节点内容自定义 <template>{{ childKeys }}<!--default-checked-keys:默认展开值(正常来说需要包含父级id的 但是我们后端不要后端id )show-checkbox&#x…...

代码随想录-算法训练营day41(动态规划04:01背包,01背包滚动数组,分割等和子集)
第九章 动态规划part04● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集 正式开始背包问题,背包问题还是挺难的,虽然大家可能看了很多背包问题模板代码…...

c#中context.SaveChanges()方法
跟踪实体的状态: Entity Framework 使用 Change Tracker 来跟踪上下文中所有实体的状态。实体的状态可以是: Added:新添加的实体(即将插入到数据库中)。Modified:已修改的实体(即将更新数据库中…...

李飞飞首个“空间智能”模型发布:一张图,生成一个3D世界 | LeetTalk Daily
“LeetTalk Daily”,每日科技前沿,由LeetTools AI精心筛选,为您带来最新鲜、最具洞察力的科技新闻。 在人工智能技术迅速发展的背景下,李飞飞创立的世界实验室于近期发布了首个“空间智能”模型,这一创新成果引发了3D生…...

Node.js简单接口实现教程
Node.js简单接口实现教程 1. 准备工作 确保您的计算机已安装: Node.js (建议版本16.x以上)npm (Node包管理器) 2. 项目初始化 # 创建项目目录 mkdir nodejs-api-tutorial cd nodejs-api-tutorial# 初始化npm项目 npm init -y# 安装必要依赖 npm install expres…...

AIGC 012-Video LDM-更进一步,SD作者将LDM扩展到视频生成任务!
AIGC 012-Video LDM-Stable Video diffusion前身,将LDM扩展到视频生成任务! 文章目录 0 论文工作1论文方法实验结果 0 论文工作 Video LDM作者也是Stable diffusion的作者,作者在SD的架构上进行扩展,实现了视频的生成。后续在Vid…...

windows文件下换行, linux上不换行 解决CR换行符替换为LF notepad++
html文件是用回车换行的,在windows电脑上,显示正常。 文件上传到linux服务器后,文件不换行了。只有一行。而且相关js插件也没法正常运行。 用notepad查看,显示尾部换行符,是CR,这就是原因。CR是不被识别的。…...

npm, yarn, pnpm之间的区别
前言 在现代化的开发中,一个人可能同时开发多个项目,安装的项目越来越多,所随之安装的依赖包也越来越臃肿,而且有时候所安装的速度也很慢,甚至会安装失败。 因此我们就需要去了解一下,我们的包管理器&#…...

静态链接和动态链接的特点
静态链接 链接方式:在编译时,所有依赖的库代码被直接打包到生成的可执行文件中。这意味着在程序运行时,不需要再加载任何外部库文件。 优点: 独立性强:生成的可执行文件可以在没有依赖库的系统上直接运行&am…...

Mac曲线救国实现Bandizip右键一级菜单
一、前言 个人认为:Bandizip是Mac上最好用的压缩软件,没有之一。 在Mac系统上,学习版的Bandizip由于签名检验问题无法在访达右键的一级菜单显示 解压相关菜单。 有能力的,希望还是支持正版,找找优惠渠道应该100左右。…...

进度与预算
一个项目,如果进度上可以按时完成,一般来说预算不会超标,或者超标幅度有限。 一个项目,如果进度上严重超期,预算基本上会超标,而且超标很大。 现在很多项目,人力成本占比都比较大,…...

【教程】创建NVIDIA Docker共享使用主机的GPU
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 这套是我跑完整理的。直接上干货,复制粘贴即可! # 先安装toolkit sudo apt-get update sudo apt-get install -y ca-certifica…...

CEEMDAN-CPO-VMD二次分解(CEEMDAN+冠豪猪优化算法CPO优化VMD)
CEEMDAN-CPO-VMD二次分解(CEEMDAN冠豪猪优化算法CPO优化VMD) 目录 CEEMDAN-CPO-VMD二次分解(CEEMDAN冠豪猪优化算法CPO优化VMD)效果一览基本介绍程序设计参考资料 效果一览 基本介绍 首先运用CEEMDAN对数据进行一次分解ÿ…...

图论理论基础和存储方式的实现
图论1 图论 (Graph theory) 是数学的一个分支,图是图论的主要研究对象。图 (Graph) 是由若干给定的顶点及连接两顶点的边所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系。顶点用于代表事物,连接两顶点的边则用于表示两个事物…...

【实分析】【二】2.2 (c)自然数的序
文章目录 前言一、自然数的序的定义二、自然数的序的基本性质三、序的三歧性四、强归纳法原理总结 前言 在2.2 (b)的末尾,我们定义了自然数的正性,现在,我们来定义自然数的序,它是一种自然数的二元关系,通过加法进行定…...

STM32串口接收与发送(关于为什么接收不需要中断而发生需要以及HAL_UART_Transmit和HAL_UART_Transmit_IT的区别)
一、HAL_UART_Transmit和HAL_UART_Transmit_IT的区别 1. HAL_UART_Transmit_IT(非阻塞模式): HAL_UART_Transmit_IT 是非阻塞的传输函数,也就是说,当你调用 HAL_UART_Transmit_IT 时,它不会等到数据完全发…...