zoukankan      html  css  js  c++  java
  • Linux 信号详解五(信号阻塞,信号未决)

    信号在内核中的表示
    执行信号的处理动作成为信号递达(Delivery),信号从产生到递达之间的状态称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。
    被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作
    注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作
    信号不会丢失,如果信号被阻塞,只会保持信号未决,但是信号不丢失
    只要取消阻塞 信号依然会到来
    ①PCB进程控制块中有信号屏蔽状态字(block),信号未决状态字(pending)还有是否忽略标识
    ②信号屏蔽状态字(block):1代表阻塞,0代表不阻塞;信号未决状态字(pending):1代表未决,0代表信号递达
    ③向进程发送SIGINT,内核首先判断信号屏蔽状态字是否阻塞,如果信号屏蔽状态字阻塞,信号未决状态字(pengding)相应位置1;
    若阻塞解除,信号未决状态字(pending)相应位置0,表示信号可以递达了。 ④block状态字,pending状态都是64bit,分别代表Linux系统中的64个信号。例如SIGINT是2号信号,对应block状态字中的第二位 ⑤block状态字用户可以读写,pending状态字用户只能读,这是新号的设计机制。
    信号集操作函数(block状态字表示)
    #include <signal.h>
    int sigemptyset(sigset_t *set);
    sigset_t *set实质上是8个字节大小的变量(8个字节64bit,代表Linux的64个信号)
    sigemptyset将状态字置零
    int sigfillset(sigset_t *set);
    sigfillset将状态字全部置1(32号信号和33号信号除外int sigaddset(sigset_t *set,int signo);
    将信号signo加入到信号集set中
    int sigdelset(sigset_t *set,int signo);
    将信号signo从信号集中删除
    int sigismember(const sigset *set,int signo);
    判断signo是否在信号集中
    sigprocmask读取或者更改进程的信号屏蔽状态字(block)
    #include <signal.h>
    int sigprocmask(int how,const sigset_t *set,sigset * oset);
    成功返回0,出错返回-1
    如果oset是非空指针,则读取进程的当前信号屏蔽状态字通过oset参数传出,如果set是非空指针,则更改进程的信号屏蔽状态字,参数how只是如何更改。
    如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。 how含义
    --SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set(位或运算) --SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask^set(位异或运算) --SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,相当于mask=set
    int sigpending(sigset_t *set);
    获取信号未决状态字(pending)信息 
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <signal.h>
    
    void printsigset(const sigset_t *pset)
    {
        int i = 0;
        //遍历64个信号,
        for (; i < 64; i++)
        {
            //信号从1开始   判断哪些信号在信号未决状态字中
            if (sigismember(pset, i + 1))
                putchar('1');
            else
                putchar('0');
            //fflush(stdout);
        }
        printf("
    ");
    }
    
    void catch_signal(int sign)
    {
        switch (sign)
        {
        case SIGINT:
            printf("accept SIGINT!
    ");
            exit(0);
            break;
        case SIGQUIT:
            printf("accept SIGQUIT!
    ");
            //取消信号阻塞
            //定义信号集
            sigset_t uset;
            //清空信号集
            sigemptyset(&uset);
            //将SIGINT信号加入到信号集中
            sigaddset(&uset,SIGINT);
            //进行位异或操作,将信号集uset更新到进程控制块PCB结构中,取消阻塞信号SIGINT
            sigprocmask(SIG_UNBLOCK,&uset,NULL);
            break;
        }
    }
    
    int main(int arg, char *args[])
    {
        //定义未决信号集(pending)
        sigset_t pset;
        //定义阻塞信号集(block)
        sigset_t bset;
        //清空信号集
        sigemptyset(&bset);
        //将信号SIGINT加入到信号集中
        sigaddset(&bset, SIGINT);
        //注册信号
        if (signal(SIGINT, catch_signal) == SIG_ERR)
        {
            perror("signal error");
            return -1;
        }
        if (signal(SIGQUIT, catch_signal) == SIG_ERR)
        {
            perror("signal error");
            return -1;
        }
        //进行位或操作,将信号集bset更新到进程控制块PCB结构中,阻塞信号SIGINT(即使用户按下ctrl+c,信号也不会递达)
        sigprocmask(SIG_BLOCK, &bset, NULL);
        while (1)
        {
            /*
             * 获取当前信号未决信息,即使在sigprocmask()函数中设置了信号阻塞,
             * 但是如果没有信号的到来,信号未决状态字对应位依然是0
             * 只要有信号到来,并且被阻塞了,信号未决状态字对应位才会是1
             * */
            sigpending(&pset);
            //打印信号未决信息
            printsigset(&pset);
            sleep(2);
        }
        return 0;
    }

  • 相关阅读:
    Binary Tree Paths
    Implement Stack using Queues
    Path Sum II
    Path Sum
    Plus One
    Add Digits
    Missing Number
    H-Index II
    H-Index
    Ugly Number II
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6087098.html
Copyright © 2011-2022 走看看