• 信号的屏蔽,信号集


    1、信号集

    POSIX标准定义了数据类型sigset_t 

    #include <signal.h>

    int sigemptyset(sigset_t *set);

    初始化一个信号集,使其不包括任何信号

    int sigfillset(sigset_t *set);

    用来初始化一个信号集,使其包括所有信号

    int sigaddset(sigset_t *set, int signum);

    用来向set指定的信号集中添加由signum指定的信号

    int sigdelset(sigset_t *set, int signum);

    用来从set指定的信号集中删除由signum指定的信号

    int sigismember(const sigset_t *set, int signum);

    用来测试信号signum是否包括在set指定的信号集中

    2、信号屏蔽
    int sigpending(sigset_t *set);

    int sigsuspend(const sigset_t *mask);

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

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

    每个进程都有一个信号屏蔽码,它规定了当前阻塞而不能传递给该进程的信号集,调用函数sigprocmask可以检测或更改进程的信号屏蔽码。

    如果oldset是非空的,则该进程之前的信号屏蔽码通过oldset返回;如果参数set是非空指针,则该函数将根据参数how来修改当前屏蔽码,how

    的取值如下:

    The behavior of the call is dependent on the value of how, as follows.

    SIG_BLOCK
    The set of blocked signals is the union of the current set and the set argument.

    将进程新的信号屏蔽码设置为当前信号屏蔽码和set指向信号集的并集

    SIG_UNBLOCK
    The signals in set are removed from the current set of blocked signals. It is permissible to attempt to unblock a signal which is not blocked.

    将进程新的信号屏蔽码设置为当前信号屏蔽码中,删除set所指向信号集,即set包含了我们希望解除阻塞的信号。即使

    对当前信号屏蔽码中不存在的信号使用SIG_UNBLOCK也是合法操作。

    SIG_SETMASK
    The set of blocked signals is set to the argument set.

    将进程新的信号屏蔽码设置为set指向的值

    (2)sigpending函数int sigpending(sigset_t *set);

    函数sigpending用来获取调用进程因被阻塞而不能传递和当前未决的信号集。该信号集通过参数set返回

    #include <stdio.h>
    #include <signal.h>
    
    void hand_signal(int signo)
    {
        printf("rece SIGINT
    ");
    }
    
    
    int main()
    {
        sigset_t newmask, oldmask, pendmask;
    
        signal(SIGINT, hand_signal);
    
        //收到信号之后会被唤醒
        sleep(30);
    
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGINT);
    
        //屏蔽信号SIGINT
        sigprocmask(SIG_BLOCK, &newmask, &oldmask);
    
        //不会被SIGINT信号唤醒
        sleep(10);
    
        //获取未决信号队列
        sigpending(&pendmask);
        //检查未决信号队列中是否有SIGINT
        switch(sigismember(&pendmask, SIGINT))
        {
            case 0:
            {
                printf("the SIGINT is not in pending queue
    ");
                break;
            }
            case 1:
            {
                printf("the SIGINT is in pending queue
    ");
                break;
            }
            default:
                break;
        }
    
        //恢复屏蔽码
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
    
    
        while(1);
    
        return 0;
    }

    (3)sigsuspend函数int sigsuspend(const sigset_t *mask);

    将进程的信号屏蔽码设置为mask,然后与pause函数一样等待信号的发生并执行完信号处理函数。

    信号处理函数执行完后再把进程的信号屏蔽码设置为原来的屏蔽字,然后sigpending函数才返回。

    sigpending函数保证改变进程的屏蔽码和将进程挂起等待信号是原子操作。

    #include <stdio.h>
    #include <signal.h>
    
    void hand_signal(int signo)
    {
        printf("rece SIGINT
    ");
    }
    
    
    int main()
    {
        sigset_t newmask, oldmask, zeromask;
    
        signal(SIGINT, hand_signal);
    
        sigemptyset(&newmask);
        sigemptyset(&zeromask);
        sigaddset(&newmask, SIGINT);
    
        //屏蔽信号SIGINT
        sigprocmask(SIG_BLOCK, &newmask, &oldmask);
    
        //临界区
        //使用sigsuspend取消所有信号的屏蔽并等待信号的触发
        sigsuspend(&zeromask);
    
        /*
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
        pause();
        */
    
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
    
    
        while(1);
    
        return 0;
    }

    如果使用

        sigprocmask(SIG_SETMASK, &oldmask, NULL);
        pause();
    会存在潜在debug,如果信号发生在sigprocmask之后,pause之前,则这个信号就会丢失掉了,且如果信号只发生一次,程序将永远挂起在pause上。
     
  • 相关阅读:
    Vue.js中使用iView日期选择器并设置开始时间结束时间校验
    侠客行
    myJRebel 已不可用
    开发.NET Core NuGet包并实现CI/CD
    独立部署GeoWebCache
    GeoServer中GeoWebCache(GWC)的使用
    使用VS Code编写Markdown文件
    GitHub团队协作流程
    打包发布到NPM并通过CDN访问
    使用VS Code编写Markdown文件
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/6693943.html
Copyright © 2020-2023  润新知