信号集

本文详细介绍了Linux中信号集的概念,包括如何使用sigset_t结构体表示信号集,以及相关函数如sigemptyset、sigfillset、sigaddset、sigdelset和sigprocmask的用法。通过示例演示了如何设置和恢复信号屏蔽,以控制进程对特定信号的响应。同时,还展示了如何使用sigismember检查信号是否在信号集中。
摘要由CSDN通过智能技术生成
一:信号集
	一个进程,必须能够记住这个进程当前阻塞了哪些信号。
	000000000000000000000
	我们需要 “信号集 ”的这么一种数据类型(结构),能够把这60多个信号都表示下(都装下)。
0000000000,0000000000,0000000000,00,0000000000,0000000000,0000000000,0064个二进制位)
linux 是用sigset_t结构类型来表示信号集的;
	typedef struct{
	unsigned long sig[2];
	}sigset_t
信号集的定义:信号集表示一组信号的来(1)或者没来(0)
信号集相关的数据类型: sigset_t;

二:信号相关函数
	(a)sigemtpyset():把信号集中的所有信号都清0,表示这60多个信号都没有来;
	(b)sigfillset();把信号集中的所有信号都设置为1,跟sigemptyset()正好相反;
	(c)sigaddset(),sigdelset()就可以往信号集中增加信号,或者从信号集中删除特定信号;
	(d)sigprocmask,sigmember
	一个进程,里边会有一个信号集,
	用来记录当前屏蔽(阻塞)了哪些信号;
	如果我们把这个信号集中的某个信号位
	设置为1,就表示屏蔽了同类信号,
	此时再来个同类信号,那么同类信号
	会被屏蔽,不能传递给进程;
	如果这个信号集中有很多个信号
	位都被设置为1,那么所有这些
	被设置为1的信号都是属于当
	前被阻塞的而不能传递到该进程的信号;
	sigprocmask()函数,就能够设置该进程     所对应的信号集中的内容;

三:sigprocmask等信号函数范例演示
    sleep()函数能够被打断:
	(1)时间到达了;
	(2)来了某个信号,使sleep()提前结束,此时sleep会返回一个值,这个值就是未睡够的时间;

范例演示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

//信号处理函数
void sig_quit(int signo)
{   
    printf("收到了SIGQUIT信号!\n");

    /*如果再次收到SIGQUIT信号,就用缺省动作处理*/
    /*if(signal(SIGQUIT,SIG_DFL) == SIG_ERR)
    {
        printf("无法为SIGQUIT信号设置缺省处理(终止进程)!\n");
        exit(1);
    }*/
}

int main(int argc, char *const *argv)
{
    /*信号集,新的信号集,原有的信号集*/
    sigset_t newmask,oldmask;
    sigset_t pendmask;

    sigaddset(&pendmask,SIGQUIT); 
    /*判断这个信号是否属于这个信号集*/
    if(sigismember(&pendmask,SIGQUIT) > 0)
    {
        printf("---------------\n");
    }

    /*注册信号对应的信号处理函数,"ctrl+\" */ 
    if(signal(SIGQUIT,sig_quit) == SIG_ERR)  
    {        
        printf("无法捕捉SIGQUIT信号!\n");
        exit(1);   
        /*退出程序,参数是错误代码,0表示正常退出,
        非0表示错误,但具体什么错误,
        没有特别规定,这个错误代码一般也用不到,先不管他;*/
    }

    /*newmask信号集中所有信号都清0,表示这些信号都没有来*/
    sigemptyset(&newmask);
    /*设置newmask信号集中的SIGQUIT信号位为1,
    说白了,再来SIGQUIT信号时,进程就收不到,设置为1就是该信号被阻塞掉呗*/
    sigaddset(&newmask,SIGQUIT); 

    /*sigprocmask():设置该进程所对应的信号集*/
    /*第一个参数用了SIG_BLOCK表明设置进程新的信号屏蔽字,
    一个 ”进程“ 的当前信号屏蔽字,刚开始全部都是0的;
    所以相当于把当前 "进程"的信号屏蔽字设置成 newmask(屏蔽了SIGQUIT);
    为 “当前信号屏蔽字 和 第二个参数指向的信号集的并集,第三个参数不为空,
    则进程老的(调用本sigprocmask()之前的)信号集会保存到第三个参数里,
    用于后续,这样后续可以恢复老的信号集给进程*/
    if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)
    {                                                
        printf("sigprocmask(SIG_BLOCK)失败!\n");
        exit(1);
    }

    printf("我要开始休息10秒了--------begin--,此时我无法接收SIGQUIT信号!\n");
    /*这个期间无法收到SIGQUIT信号的*/
    sleep(10); 

    printf("我已经休息了10秒了--------end----!\n");
    
    //测试一个指定的信号位是否被置位(为1),测试的是newmask
    if(sigismember(&newmask,SIGQUIT))
    {
        printf("SIGQUIT信号被屏蔽了!\n");  //ok
    }
    else
    {
        printf("SIGQUIT信号没有被屏蔽!!!!!!\n");
    }

    /*测试另外一个指定的信号位是否被置位,测试的是newmask*/
    if(sigismember(&newmask,SIGHUP))  
    {
        printf("SIGHUP信号被屏蔽了!\n");
    }
    else
    {
        printf("SIGHUP信号没有被屏蔽!!!!!!\n"); //ok
    }

    //现在我要取消对SIGQUIT信号的屏蔽(阻塞)--把信号集还原回去
    /*第一个参数用了SIGSETMASK表明设置进程新的信号屏蔽字
    为第二个参数指向的信号集,第三个参数没用*/

    /*如果在恢复之前,不管有多少个SIGQUIT信号来,系统都会当成是一个SIGQUIT信号
    在以上sleep的时候,如果来了一个SIGQUIT信号,那么由于已经屏蔽了该信号,所以
    不会收到该信号,在恢复了老的信号集以后,可以观察到,只执行了一次信号发生函数*/
    if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0) 
    {
        printf("sigprocmask(SIG_SETMASK)失败!\n");
        exit(1);
    }

    printf("sigprocmask(SIG_SETMASK)成功!\n");
    
    /*测试一个指定的信号位是否被置位,这里测试的当然是oldmask*/
    if(sigismember(&oldmask,SIGQUIT))  
    {
        printf("SIGQUIT信号被屏蔽了!\n");
    }
    else
    {
        printf("SIGQUIT信号没有被屏蔽,您可以发送SIGQUIT信号了,我要sleep(10)秒钟!!!!!!\n");
        int mysl = sleep(10); //可以被信号打断
        if(mysl > 0)
        {
            printf("sleep还没睡够,剩余%d秒\n",mysl);
        }
    }
    printf("再见了!\n");
    return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值