信号集、sigprocmask函数、sigemptyset/sigfillset函数、sigaddset/sigdelset函数

1.信号集

一个进程必须能够记住这个进程当前阻塞了哪些信号,因此,一个进程里边会有一个信号集,用来记录当前屏蔽(阻塞)了哪些信号。

如果我们把这个信号集中的某个信号位设置为 1 1 1,就表示屏蔽了同类信号,此时再来个同类信号,那么同类信号会被屏蔽,不能传递给进程。

如果这个信号集中有很多个信号位都被设置为 1 1 1,那么所有这些被设置为 1 1 1 的信号都是属于当前被阻塞的而不能传递到该进程的信号。

Linux 是用 sigset_t 结构类型来表示信号集的,能够把 60 多个信号都表示下(都装下)。

2.信号函数范例演示

sigemptyset 函数:把信号集中的所有信号都清 0 0 0,表示这 60 60 60 多个信号都没有来。

sigfillset 函数:把信号集中的所有信号都设置为 1 1 1,跟 sigemptyset 函数正好相反。

sigaddset 函数:往信号集中增加信号。

sigdelset 函数:从信号集中删除特定信号。

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

//信号处理函数
void sig_quit(int signo)
{
    printf("收到了SIGQUIT信号!\n");
    if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
    {
        printf("无法为SIGQUIT信号设置缺省处理(终止进程)!\n");
        exit(1);
    }
}

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

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

    sigaddset(&newmask, SIGQUIT); // 设置newmask信号集中的SIGQUIT信号位为1,设置为1就是该信号被阻塞掉,即再来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");

    sleep(10); // 这个期间是无法收到SIGQUIT信号的
    
    printf("我已经休息了10秒了--------end--------!\n");
    
    if (sigismember(&newmask, SIGQUIT)) // 测试某个指定的信号位是否被置位(置1),测试的是newmask
    {
        printf("SIGQUIT信号被屏蔽了!\n");
    }
    else
    {
        printf("SIGQUIT信号没有被屏蔽!!!!!!\n");
    }

    if (sigismember(&newmask, SIGHUP)) // 测试另外一个指定的信号位是否被置位,测试的是newmask
    {
        printf("SIGHUP信号被屏蔽了!\n");
    }
    else
    {
        printf("SIGHUP信号没有被屏蔽!!!!!!\n");
    }
    
    // 现在我要取消对SIGQUIT信号的屏蔽(阻塞),把信号集还原回去
    // 第一个参数用了SIGSETMASK,表明设置进程新的信号屏蔽字为第二个参数指向的信号集,第三个参数没用
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
    {
        printf("sigprocmask(SIG_SETMASK)失败!\n");
        exit(1);
    }
    
    printf("sigprocmask(SIG_SETMASK)成功!\n");
    
    if (sigismember(&oldmask, SIGQUIT)) // 测试某个指定的信号位是否被置位,这里测试的当然是oldmask
    {
        printf("SIGQUIT信号被屏蔽了!\n");
    }
    else
    {
        printf("SIGQUIT信号没有被屏蔽,您可以发送SIGQUIT信号了,我要sleep(10)秒钟!!!!!!\n");

        int mysl = sleep(10);
        
        // sleep()函数能够被打断:
        // (1)时间到达了;
        // (2)来了某个信号,使sleep()提前结束,此时sleep()会返回一个值,这个值就是未睡够的时间;

        if (mysl > 0)
        {
            printf("sleep还没睡够,剩余%d秒\n", mysl);
        }
    }

    printf("再见了!\n");
    
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值