【Linux】信号的阻塞-在内核中的表示方式
创始人
2025-06-01 15:17:59
0

文章目录

  • 阻塞信号
    • 信号其他相关常见概念
    • 在内核中的表示方式
      • 总结
    • sigset_t-信号集
    • 信号集操作函数
      • sigprocmask
      • sigpending
      • 运用小例子

阻塞信号

信号其他相关常见概念

1)实际执行信号的处理动作,称为信号递达(Delivery)

2)信号从产生到递达之间的状态,称为信号未决(pending)

3)进程可以选择阻塞(Block)某个信号

4)被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作

5)需要注意的是,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后的一种处理动作


在内核中的表示方式

image-20220816093704901

  1. 每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作…信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志…

例如:在上图中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作…


2)SIGINT信号产生过,但正在被阻塞,所以暂时不能递达…虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会在改变处理动作之后再解除阻塞

3)SIGQUIT信号未产生过,但一旦产生SIGQUIT信号,该信号将被阻塞,它的处理动作是用户自定义函数sighandler

如果在进程解除对某信号的阻塞之前,这种信号产生过多次,如何处理?(例如:POSIX.1允许系统递送该信号一次或多次)

Linux是这样实现的:普通信号在递达之前产生多次只计一次,实时信号在递达之前产生多次可以依次放在一个队列里,我们只讨论普通信号


总结

1.在block位图中,比特位的位置代表某一个信号,比特位的内容代表该信号是否被阻塞 (0/1) (block位图:也叫做信号屏蔽字)

2.在pending位图中,比特位的位置代表某一个信号,比特位的内容代表是否收到该信号(0/1)

3.handler表本质上是一个函数指针数组,数组的下标代表某一个信号,数组的内容代表该信号递达时的处理动作,处理动作包括默认, 忽略以及自定义

4.block、pending和handler这三张表的每一个位置是一一对应的


sigset_t-信号集

根据信号在内核中的表示方法,每个信号的未决标志只有1个比特位,非0即1,如果不记录该信号产生多少次,那么阻塞标志也只有一个比特位

因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储, 其中sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态

  • 在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞
    • 阻塞信号集也叫做当前进程的信号屏蔽字,这里的“屏蔽”应该理解为阻塞而不是忽略
  • 在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态

在Linux中,其定义如下:

#define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;
typedef __sigset_t sigset_t;

信号集操作函数

sigset_t类型对于每种信号用一个bit表示“有效”或“无效”,至于这个类型内部如何存储这些bit则依赖于系统的实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义

#include 
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
函数作用返回值
sigemptyset函数初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号成功返回0,出错返回-1
sigfillset函数初始化set所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括系统支持的所有信号成功返回0,出错返回-1
sigaddset函数在set所指向的信号集中添加某种有效信号成功返回0,出错返回-1
sigdelset函数在set所指向的信号集中删除某种有效信号成功返回0,出错返回-1
sigismember函数判断在set所指向的信号集中是否包含某种信号若包含则返回1,不包含则返回0,调用失败返回-1

注意:在使用sigset_t类型的变量之前,一定要调用sigemptyset或sigfillset做初始化,使信号处于确定的状态


小例子

#include 
#include 
int main()
{sigset_t set; //定义一个类型为信号集的变量//初始化,使信号处于确定的状态sigemptyset(&set);sigfillset(&set);sigaddset(&set, SIGINT);//在set所指向的信号集中添加有效信号SIGINTsigdelset(&set, SIGINT);//在set所指向的信号集中删除有效信号SIGINTsigismember(&set, SIGINT);//判断在set所指向的信号集中是否包含SIGINT信号return 0;
}

代码中定义的sigset_t类型的变量s,与我们平常定义的变量一样都是在用户空间定义的变量,后面我们用信号集操作函数对变量s的操作实际上只是对用户空间的变量s做了修改,并不会影响进程的任何行为,我们还需要通过系统调用,才能将变量s的数据设置进操作系统


sigprocmask

sigprocmask函数可以用于读取或更改进程的信号屏蔽字(阻塞信号集)

#include
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

参数说明:

第一个参数how: 假设当前的信号屏蔽字为mask,how参数的可选值及其含义

选项含义
SIG_BLOCKset包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set
SIG_UNBLOCKset包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask|~set
SIG_SETMASK设置当前信号屏蔽字为set所指向的值,相当于mask=set

第二个和第三个参数:

如果oldset是非空指针,则读取进程当前的信号屏蔽字通过oldset参数传出

如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改

如果oldset和set都是非空指针,则先将原来的信号屏蔽字备份到oldset里,然后根据set和how参数更改信号屏蔽字


返回值说明 : sigprocmask函数调用成功返回0,失败返回-1

函数注意事项 如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask函数返回前,至少要将其中一个信号递达


sigpending

sigpending函数可以用于读取当前进程的未决信号集

#include
int sigpending(sigset_t *set);	

set是输出型参数,读取当前进程的未决信号集,并通过set参数传出

返回值: 函数调用成功返回0,失败返回-1


运用小例子

1)利用sigprocmask函数,将2号信号进行屏蔽(阻塞) 2)使用kill命令或组合按键向进程发送2号信号

3)此时2号信号会一直被阻塞,并一直处于pending(未决)状态 4)使用sigpending函数获取当前进程的pending信号集进行验证

#include 
#include 
#include 
void printPending(sigset_t *pending)
{int i = 1;for (i = 1; i <= 31; i++){//判断在set所指向的信号集中是否包含编号为i的信号if (sigismember(pending, i)){printf("1 ");}else{printf("0 ");}}printf("\n");
}   
int main()
{	sigset_t set, oset;//初始化信号集sigemptyset(&set);sigemptyset(&oset);sigaddset(&set, 2); //在set所指向的信号集中添加有效信号-2号信号SIGINTsigprocmask(SIG_SETMASK, &set, &oset); //阻塞2号信号sigset_t pending;sigemptyset(&pending); //初始化信号集while(1){sigpending(&pending); //获取pending位图printPending(&pending); //打印pending位图(比特位为1表示未决状态)sleep(3);}return 0;
}
image-20220816104151348

程序刚刚开始运行时:因为没有收到任何信号,所以此时该进程的pending表一直是全0,而当我们使用kill命令向该进程发送2号信号后,由于2号信号是阻塞的,因此2号信号一直处于未决状态,所以我们看到pending表中的第二个元素就变成1了


我们可以设置一段时间后解除对2号信号的阻塞状态,然后2号信号就会立即被递达,由于2号信号的默认处理动作是终止进程,所以为了看到2号信号递达后的pending表,我们可以将2号信号进行捕捉,让2号信号递达时执行我们所给的自定义动作

void printPending(sigset_t *pending)
{int i = 1;for (i = 1; i <= 31; i++){//判断在set所指向的信号集中是否包含编号为i的信号if (sigismember(pending, i)){printf("1 ");}else{printf("0 ");}}printf("\n");
}  
//自定义捕获方法
void handle(int signo)
{printf("receive a %d signnal\n",signo);
}
int main()
{signal(2,handle);//捕获2号信号sigset_t set, oset;//初始化信号集sigemptyset(&set);sigemptyset(&oset);sigaddset(&set, 2); //在set所指向的信号集中添加有效信号-2号信号SIGINT//此时oldset和set都是非空指针,则先将原来的信号屏蔽字(全0)备份到oldset里,然后根据set和how参数更改信号屏蔽字sigprocmask(SIG_SETMASK, &set, &oset); //阻塞2号信号sigset_t pending;sigemptyset(&pending); //初始化信号集int count = 0;while(1){sigpending(&pending); //获取pending位图printPending(&pending); //打印pending位图(比特位为1表示未决状态)sleep(3);count++;if(5== count){//此时set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改//设置当前信号屏蔽字为set所指向的值,相当于mask=osetsigprocmask(SIG_SETMASK, &oset, NULL); //恢复曾经的信号屏蔽字 ->即oset//细节:先递达信号再打印 printf("恢复信号屏蔽字\n");}}return 0;
}

注意:这里有个细节:我们是先解除对当前若干个未决信号的阻塞,然后再打印

因为: 如果调用sigprocmask解除对当前若干个未决信号的阻塞,则在sigprocmask函数返回前,至少将其中一个信号递达

image-20220816110913710

当进程收到2号信号后,该信号在一段时间内处于未决状态,当解除2号信号的屏蔽后,2号信号就会立即递达,执行我们所给的自定义动作,而此时的pending表也变回了全0

相关内容

热门资讯

日常等车时看到的行业细节 干了五年户外广告投放,养成了一个职业病:但凡路过公交候车亭,总会多看两眼——不是看广告好不好看,而是...
黄金回收行业标准制定有哪些核心... 贵金属回购市场的需求背景 近年来随着黄金投资和消费市场的发展,黄金回收相关需求持续攀升。不同群体的诉...
全球黑色星期二!AI交易“崩盘... 【导读】AI交易为何“崩盘”? 中国基金报记者 泰勒 大家,你们今天还好吗?! AI交易在全球范围内...
原创 6... 年初抢金条的人还在站岗,如今金店柜台前冷冷清清 黄金又跌了。 6月23日,伦敦现货黄金价格日内急跌逾...
狂融294亿美元!SK海力士冲... 韩国股市再度迎来重磅消息。 周三,韩国存储芯片龙头SK海力士宣布,计划在7月10日登陆纳斯达克,通过...
比特币跌破6万!AI吸走资金、... 比特币正在为机构化转型付出代价。散户买盘萎缩、ETF资金持续外流、企业持仓者潜在抛售压力上升,加之A...
原创 默... 欧洲近期试图复刻1985年广场协议的剧本,德国总理默茨呼吁欧盟27国联合行动,要求中国签订类似协议以...
怎么选 泛娱乐赛道直播公司孵化... 泛娱乐直播创业的行业发展背景 近年来泛娱乐直播赛道持续保持增长态势,据公开数据资料显示,2024年国...
原创 腰... 最近黄金市场凉得彻底。各大品牌足金饰品克价跌破1300元关口,北京菜百6月21日报价已经掉到1260...
ST中装:公司主要银行账户已全... 证券之星消息,ST中装(002822)06月24日在投资者关系平台上答复投资者关心的问题。 投资者提...
2026年开窗机行业趋势与战略... 一、开篇引言:市场格局重塑下的选择逻辑 步入2026年,全球建筑智能化与绿色节能政策的叠加驱动,使开...
资金全面转向科技,传统消费企业... 近期 A 股出现明显风格切换,老牌消费资金持续流出,机构与传统上市公司纷纷加码半导体、算力赛道。 先...
合肥保利翡翠天奕具体交房时间是... 对于众多购房者而言,“合肥保利翡翠天奕具体交房时间是什么时候?能按时交房吗?”是心中最关切的问题。根...
港股风向标|恒指连续杀跌后企稳... 财联社6月24日讯(编辑 冯轶)今日港股短线企稳,三大指数集体收涨。截至收盘,恒生指数涨0.33%,...
瑞众人寿达州中支被罚17万,涉... 蓝鲸新闻6月24日讯,近日,国家金融监督管理总局达州监管分局发布行政处罚决定书,剑指瑞众人寿保险有限...
美国最担心的事还是来了,中国加... 最近这段时间,国际金融圈子里有一笔账,算得各家央行心里都不太踏实。 截至2026年春季,美国国债总规...
马斯克,不是万亿富豪了 资产历史性超过万亿美元不到两周,特斯拉、SpaceX掌门人埃隆·马斯克的身价近日快速下跌。 据中新经...
突发!金价跌破4000美元,近... 每经记者:杜宇 记者|杜宇 编辑|何小桃 杜恒峰 校对|金冥羽 金银价格大跳水。 6月24日晚,现货...
粗粮吃越多越好?很多糖友吃错升... 控糖圈一直流传多吃粗粮稳血糖,不少糖友直接三餐全吃粗粮、顿顿杂粮,不仅胃胀消化不良,餐后血糖反而不降...
持续大跌!刚刚,黄金跌破400... 潮新闻客户端 记者 吴恩慧 6月24日,贵金属再次大跌。 截至发稿时,现货黄金大跌近3%,跌破400...