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…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
