• linux信号--阻塞与未决


    执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)

    进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

    1:PCB进程控制块中函数有信号屏蔽状态字(block)信号未决状态字(pending)还有是否忽略标志(或是信号处理函数);block状态字、pending状态字 64bit;

    2:信号屏蔽状态字(block),1代表阻塞、0代表不阻塞;信号未决状态字(pending)的1代表未决,0代表信号可以抵达了;它们都是每一个bit代表一个信号,比如,bit0代表信号SIGHUP;

    3:比如向进程发送SIGINT,内核首先判断信号屏蔽状态字是否阻塞,如果该信号被设为为了阻塞的,那么信号未决状态字(pending)相应位制成1;若该信号阻塞解除,信号未决状态字(pending)相应位制成0;表示信号此时可以抵达了,也就是可以接收该信号了。

     4:屏蔽状态字用户可以读写,未决状态字用户只能读(?);这是信号设计机制。

    信号集操作函数,对状态字进行操作(屏蔽状态字和未决状态字):

    #include <signal.h>
    int sigemptyset(sigset_t *set);//将信号集清空,共64bits
    int sigfillset(sigset_t *set);//将信号集置1
    int sigaddset(sigset_t *set, int signum);//将signum对应的位置为1
    int sigdelset(sigset_t *set, int signum);//将signum对应的位置为0
    int sigismember(const sigset_t *set, int signum);//判断signum是否在该信号集合中,如果集合中该位为1,则返回1,表示位于在集合中
    还有一个函数可以读取更改屏蔽状态字的API函数

     #include <signal.h>

    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

    参数how有下面三种取值:
    SIG_BLOCK:  将参数set指向的信号集中设置的信号添加到现在的屏蔽状态字中,设置为阻塞;
    SIG_UNBLOCK:将参数set指向的信号集中设置的信号添加到现在的屏蔽状态字中,设置为非阻塞, 也就是解除阻塞;
    SIG_SETMASK:将参数set指向的信号集直接覆盖现在的屏蔽状态字的值;
    如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。
    若成功则为0,若出错则为-1

    还有一个函数可以读取未决状态字(pending)信息 
    #include <signal.h>
    int sigpending(sigset_t *set);
    SIGINT信号设置阻塞,查看未决关键字 
    发送SIGINT信号,查看未决关键字 
    发送SIGQUIT信号解除SIGINT信号阻塞,查看未决关键字 

    刚开始设置SIGINT信号为阻塞信号,当按下Ctrl+c发送中断信号SIGINT(值为2,所以后来第二位被置1)之前,未决状态字的所有位都是0,因为此时没有未抵达的信号;
    当发送SIGINT信号后,因为该信号是阻塞的,所以未决状态字将第二位置为了1,表示该信号在这里阻塞了;当我按下Ctrl+发送SIGQUIT信号后,又将SIGINT信号设置为了非阻塞的;
    此时可以看到未决状态字的所有位都变为了0;并且也收到了刚才阻塞的SIGINT信号;
    #include <iostream>
    #include <signal.h>
    #include <cstdlib>
    #include <unistd.h>
    using namespace std;
    
    
    void handler(int num)
    {
        if(num == SIGINT){
            cout << "刚才收到了信号SIGQUIT, 取消了阻塞,收到中断信号.." << endl;
        }
        else if (num == SIGQUIT){
            //将SIGINT信号设置为非阻塞的
            sigset_t un_bset;
            sigemptyset(&un_bset);
            sigaddset(&un_bset, SIGINT);
            sigprocmask(SIG_UNBLOCK, &un_bset, NULL);
        }
    }
    
    void print_pending(sigset_t * pset)
    {
        int i = 0;
        cout << "未决状态字(64位):";
        for (i = 1; i <= 64; ++i){
            if(sigismember(pset, i))
                cout << 1;
            else
                cout << 0;
            if(i % 8 == 0){
                cout << " ";
            }
        }
        cout << endl;
    }
    int main()
    {
        sigset_t bset;
        sigset_t pset;
        
        //设置SIGINT信号
        sigemptyset(&bset);
        sigaddset(&bset, SIGINT);
    
        signal(SIGINT, handler);
        signal(SIGQUIT, handler);
        //将SIGINT信号设置为阻塞的
        sigprocmask(SIG_BLOCK, &bset, NULL);
    
        while(1){
            //得到未决状态字
            sigpending(&pset);
            //显示未决状态字
            print_pending(&pset);
    
            sleep(1);
        }
    
    
        exit(0);
    }
     
  • 相关阅读:
    margin:0 auto; 为什么会失效
    vue 登录滑块验证
    layui table 添加序号列
    纯css :after 菜单后面添加“<”
    设置div为不可点击
    ubuntu中root用户在图形界面登录
    ubuntu root用户无法登录filezilla的问题
    ubuntu无法用putty登录
    解决ubuntu和windows电脑之间无法复制粘贴问题
    E: Unable to locate package ubuntu
  • 原文地址:https://www.cnblogs.com/guxuanqing/p/11218720.html
Copyright © 2020-2023  润新知