信号的屏蔽和安装

一、关于信号的介绍

参见信号的的介绍

二、信号的屏蔽和捕捉忽略

SIGKILLSIGDTOP信号外。其他的信号都可以被屏蔽或者忽略。

  • 信号忽略:系统仍然传递该信号,只是相应的进程对该信号不做任何处理。
  • 信号的屏蔽:该进程对该信号不捕获,而是让该信号处于未决状态。只有当进程的信号集发生改变后,不再屏蔽该信号,才捕获信号。
    信号的屏蔽只是待信号发生后,让信号处于未决状态,将信号处理进行延后(延至解除屏蔽)再处理,信号的忽略表示自己捕获到该信号,在信号处理函数中什么为也不干直接忽略

1、信号的捕获

参见信号的捕获处理

2、信号的屏蔽

①、信号集

信号集,顾名思义所有信号的集合。在Linux下信号的集合是sigset_t类型的变量,该类型的定义为unsigned long int的,该类型在GCC(POSIX系统以及Cygwin)下为8字节。而Linux下一共64个信号,这代表着每个信号占一位(1bit)。当该信号集的第一个bit为1时,表示1号信号处于未决态(被屏蔽准确不应该这么叫),为0时表示1号信号未处于未决态(未被屏蔽)。
信号集的本质是位图,我们在操作信号集的时候不应该直接使用位操作,而是用响应的API操作,保证程序跨平台的有效。

②、信号集的相关操作

(1)将某个信号集清0
int sigemptyset(sigset_t *set);
成功:0
失败:-1
(2)将某个信号集置1
int sigfillset(sigset_t *set);
成功:0
失败:-1
(3)将某个信号加入到信号集
 int sigaddset(sigset_t *set, int signum);
 成功:0
失败:-1
(4)将某个信号从信号集清除
int sigdelset(sigset_t *set, int signum);
 成功:0
失败:-1
(5)判断某个信号是否在信号集中
int sigismember(const sigset_t *set, int signum);
在:1	不在:	0出错:-1
(6)设置进程屏蔽信号集

用来屏蔽/解除屏蔽位于进程PCB中的信号集合


int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
假设当前的信号集合为currmask
how参数的取值:
			SIG_BLOCK:表示将set信号集合添加到当前进程屏蔽的信号集中,相当于currmask=currmask|set
			SIG_UNBLOCK:表示将set信号集合从当前进程屏蔽的信号集中删除,相当于currmask = currmask&~set
			SIG_SETMASK:表示用set替代原来的屏蔽信号集
       set:表示当前要设置的屏蔽的信号集
	oldset:表示设置前的屏蔽的信号集
(7)获取当前进程未决信号集

任何发送给进程没有被捕获的信号成为未决信号,这里包含没来得及处理(正在处理其他信号)信号和因进程暂时屏蔽了这和信号而导致的未决。

int sigpending(sigset_t *set);
传出当前的未决信号集,该信号集的那个bit位为1,表示那个信号被屏蔽。
返回值:成功:0;失败:-1

③、屏蔽信号的示例

(1)示例一:

在下面的示例中,屏蔽3号信号SIGQUIT(该信号由键盘ctrl+/产生),屏蔽2号信号SIGINT(该信号由键盘ctrl+c产生),屏蔽19号信号SIGTSTP(该信号由键盘ctrl+z产生),并且验证是否能屏蔽9号信号SIGKILL(该信号通过kill -9发送产生)

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


void printsigset(sigset_t *set)
{
    //64个信号太多了,只观察前32个意思意思.进程号从1开始
    for (int i = 1; i <=32; i++)
    {
        //判断信号i是否在集合中
        if(sigismember(set,i)==1)
            printf("1 ");
        else
            printf("0 ");
    }
    printf("\n");
}

int main(int argc, char const *argv[])
{
    sigset_t myset,oldset;
    int recv = 0;
    //清空myset信号集
    recv |= sigemptyset(&myset);
    //将要屏蔽的信号添加到信号集中
    recv |= sigaddset(&myset,SIGQUIT);      //ctrl+/产生
    recv |= sigaddset(&myset,SIGINT);       //ctrl+c产生
    recv |= sigaddset(&myset,SIGTSTP);      //ctrl+z产生
    recv |= sigaddset(&myset,SIGKILL);      //kill信号是不能被屏蔽的,这里验证是否能屏蔽
    if(recv!=0)
    {
        perror("sidaddset fun error\n");
        exit(0);    
    }
    //获取当前未决信号集
    sigpending(&oldset);
    printsigset(&oldset);
    //设置当前进程的屏蔽信号集
    sigprocmask(SIG_BLOCK,&myset,&oldset);
    sleep(9);
    while(1)
    {
        sleep(2);
        //获取当前未决信号集
        sigpending(&oldset);
        printsigset(&oldset);
    }

    
    return 0;
}

在这里插入图片描述

上面结果表明,当某个信号被事先加入到进程的屏蔽信号集中后。当该信号产生时,进程的未决信号集的相应位会被置1,同时该信号就会处于未决态。而当进程的信号集发生变化后(例如将该信号从进程的屏蔽信号集中剔除)后,刚处于未决态的信号就会被激活,继续执行该信号的动作。看下面的示例二

(1)示例二:

先将ctrl+c产生的2号信号加入到屏蔽信号集中,在程序运行后的1秒时按下ctrl+c 产生SIGINT 信号2。此时信号2并不能让进程结束,因为该信号处于未决态。4秒后程序运行到if语句中。将2号信号从进程的屏蔽信号集中剔除。此时刚刚处于未决态的信号2就会被激活,执行相应的信号处理函数。而信号2默认处理就是结束进程,因此进程自动结束 printf(“结束了\n”); 这行代码还未执行就结束了。

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


void printsigset(sigset_t *set)
{
    //64个信号太多了,只观察前32个意思意思.进程号从1开始
    for (int i = 1; i <=32; i++)
    {
        //判断信号i是否在集合中
        if(sigismember(set,i)==1)
            printf("1 ");
        else
            printf("0 ");
    }
    printf("\n");
}

int main(int argc, char const *argv[])
{
    sigset_t myset,oldset;
    int recv = 0;
    //清空myset信号集
    recv |= sigemptyset(&myset);
    //将要屏蔽的信号添加到信号集中
    recv |= sigaddset(&myset,SIGINT);       //ctrl+c产生
    if(recv!=0)
    {
        perror("sidaddset fun error\n");
        exit(0);    
    }
    //设置当前进程的屏蔽信号集
    sigprocmask(SIG_BLOCK,&myset,&oldset);
    while(1)
    {
        static int j =0;
        j++;
        sleep(1);
        //获取当前未决信号集
        sigpending(&oldset);
        printsigset(&oldset);
        //四秒后将该信号从进程的屏蔽信号集中剔除
        if(j == 4)
        { 
            printf("进来了\n");
            //将ctrl+c信号从当前进程的屏蔽信号集中剔除
            sigprocmask(SIG_UNBLOCK,&myset,&oldset);
            
            printf("结束了\n");    
        }
    }

    
    return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值