Linux日常——信号(2)之阻塞信号

来源:互联网 发布:java读取文件编码格式 编辑:程序博客网 时间:2024/06/05 15:48

阻塞信号

这里我们需要先了解几个基本概念
信号递达(Delivery) :实际执⾏行信号的处理动作
信号未决(Pending) :信号从产⽣生到递达之间的状态
阻塞:进程可以选择阻塞 (Block )某个信号。
被阻塞的信号产⽣生时将保持在未决状态,直到进程解除对此信号的阻塞, 才执⾏行递达的动作。

阻塞:在信号未决状态产生,此时没有对信号做出处理
忽略:在信号递达后进行,忽略也是对信号的一种处理方式(就是不做处理-_-)

每个进程的PCB块里都有3张表
block:位图,用于表示信号是否被阻塞(屏蔽)—————-阻塞
pending:位图,用于表示信号是否收到————————-未决
handler:函数指针数组,描述信号被如何处理(3种方式)——-递达
SIG_DFL:默认方式
SIG_ING:忽略方式

1,jpg
在上图的例⼦子中,
1. SIGHUP信号未阻塞也未产⽣生过,当它递达时执⾏行默认处理动作。
2. SIGINT信号产⽣生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在 没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
3. SIGQUIT信号未产⽣生过,⼀一旦产⽣生SIGQUIT信号将被阻塞,它的处理动作是⽤用户⾃自定义函数sighandler。

信号集sigset_t

这个类型可以表示每个信号的“有效”或“无效”状态,
在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞
( 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask))
在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。

产生:
Linux中规定::常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。
每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示 。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。

信号集操作函数
头文件:signal.c

int sigemptyset(sigset_t *set)
初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号

int sigfillset(sigset_t *set )
初始化set所指向的信号集,使其中所有信号的对应bit置位(全1),表示该信号集的有效信号包括系统⽀支持的所有信号

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

int sigaddset(sigset_t *set ,int signo)
向信号集中添加某种有效信号
int sigdelset (sigset_t *set ,int signo)
向信号集中删除某种有效信号

以上四个函数都是成功返回0,出错返回-1

int sigismember(const sigset_t *set ,int signo )
布尔函数,用于判断一个信号集的有效信号中是否包含某种信号
包含则返回1,不包含则返回0, 出错返回-1

int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
读取或更改进程的信号屏蔽字(阻塞信号集)
成功则为0,若出错则为-1
如果oset是⾮非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。
如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。
如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset⾥里,然后根据set和how参数更改信号屏蔽字。

简单来说:
oset可以用来记录修改前的block,方便执行完操作后恢复之前的block
set是修改后的新block表
how是要执行的操作(3种)

  • SIG_BLOCK:添加信号到当前的block,mask=mask | set
  • SIG_UNBLOCK:解除当前block中的信号,mask=mask & ~set
  • SIG_SRTMASK:设置当前block为set指向的值, mask=set
    解释:
    mask是当前block表。它在oset中做备份,而set是新的block表,set与mask做运算
    2.jpg

以下是实现进程
在10秒内,block表屏蔽2号信号,此时间段内从键盘发送一个2号信号,pending表被设置,但信号却不会被递达,10秒结束后恢复到原来状态,信号被捕获(信号递达)

#include<stdio.h>#include<signal.h>void showpending(sigset_t *pending){    int i=1;    for(;i<=31;++i)    {      //判断i号信号是否存在于pending        if(sigismember(pending,i))        {            printf("1");        }        else{            printf("0");        }    }    printf("\n");}void handler(int sig){    printf("get a sig :%d\n",sig);}int main(){    sigset_t blockset,oblockset,pending; //设置3张表,新的block表,旧block   //初始化两张表,全置0    sigemptyset(&blockset);        sigemptyset(&oblockset);   //向block中添加2号信号,---屏蔽2号    sigaddset(&blockset,2);    signal(2,handler);    //备份原来的block(oblockset是备份),向blockset中设置屏蔽2号信号    sigprocmask(SIG_SETMASK,&blockset,&oblockset);    int count=1;    while(1)    {     //获取pending        sigpending(&pending);    //打印pending        showpending(&pending);        sleep(1);        if((count++)==10)        {            printf("return old blockset\n");           //恢复为原来的pending            sigprocmask(SIG_SETMASK,&oblockset,NULL);        }    }}

运行结果:
3.jpg

原创粉丝点击