当前位置: 首页 > news >正文

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(实现给出图集名字和图片名字生成对应的图片)

目录 实现给出图集名字和图片名字生成对应的图片&#xff1a; 代码示例&#xff1a; dic: 键 是图集名称 值是一个字典 该字典键是图片名称 值是图片&#xff0c;结构如图&#xff1a; 测试代码&#xff1a; 结果&#xff1a; SpriteRenderer 讲解&#xff1a; Resour…...

烟草行业通过Profinet转EthernetIP网关打通数据壁垒

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

2020年国赛高教杯数学建模E题校园供水系统智能管理解题全过程文档及程序

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

ip地址显示本地局域网什么意思?ip地址冲突怎么解决

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

[软件工程]八.软件演化

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

【大数据学习 | 面经】yarn的资源申请和分配的单位-Container

在yarn中&#xff0c;资源的申请和分配是以container为单位进行的&#xff0c;而不是直接以application和task为单位。 每个提交到yarn上的应用程序&#xff08;application&#xff09;都有一个对应的ApplicationMaster&#xff08;AM&#xff09;。这个AM负责与ResourceMana…...

WiFi受限不再愁,电脑无网络快速修复指南

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

【组件封装】uniapp vue3 封装一个完整的Tabs(标签页)组件教程,功能由简到杂实现讲解。

文章目录 前言一、简单版Tabs代码实现&#xff1a; 二、下划线带动画的TabsAPI回顾&#xff1a;代码实现&#xff1a; 三、内容区域滑动切换切换动画代码实现&#xff1a;&#xff08;2&#xff09;禁用手势滑动切换&#xff08;3&#xff09;内容区域换为插槽 四、标签栏可滚动…...

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辅助临床启示撰写指南 前言基础分析框架第一阶段&#xff1a;核心要素分析第二阶段&#xff1a;应用场景展开 关键环节提示第三阶段&#x…...

Pynsist 打包应用 和 PyWebIO 构建Web 应用

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

git 使用配置

新拿到机器想配置git 获取代码权限&#xff0c;需要的配置方法 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’。错误信息的字面意思是&#xff1a;表“table_name”拒绝用户“user_name”“1.1.1.1”的SELECT命令 。 比较多的情况是&#xff1a;用户没有查看user表…...

element-plus的el-tree的双向绑定

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

代码随想录-算法训练营day41(动态规划04:01背包,01背包滚动数组,分割等和子集)

第九章 动态规划part04● 01背包问题&#xff0c;你该了解这些&#xff01; ● 01背包问题&#xff0c;你该了解这些&#xff01; 滚动数组 ● 416. 分割等和子集 正式开始背包问题&#xff0c;背包问题还是挺难的&#xff0c;虽然大家可能看了很多背包问题模板代码&#xf…...

c#中context.SaveChanges()方法

跟踪实体的状态&#xff1a; Entity Framework 使用 Change Tracker 来跟踪上下文中所有实体的状态。实体的状态可以是&#xff1a; Added&#xff1a;新添加的实体&#xff08;即将插入到数据库中&#xff09;。Modified&#xff1a;已修改的实体&#xff08;即将更新数据库中…...

李飞飞首个“空间智能”模型发布:一张图,生成一个3D世界 | LeetTalk Daily

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

Node.js简单接口实现教程

Node.js简单接口实现教程 1. 准备工作 确保您的计算机已安装&#xff1a; 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前身&#xff0c;将LDM扩展到视频生成任务&#xff01; 文章目录 0 论文工作1论文方法实验结果 0 论文工作 Video LDM作者也是Stable diffusion的作者&#xff0c;作者在SD的架构上进行扩展&#xff0c;实现了视频的生成。后续在Vid…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...