• 信号应用于事件通知


    实际应用中,进程常常需要等待某一事件的发生,一般可以通过检测某一全局变量来判断事件是否发生。

    有3种方法可以实现这一要求:

    1、

    程序不停的循环检查全局变量,这样可以满足要求,但是非常占用CPU资源。

    2、

    进程使用pause挂起,等待信号的触发,事件发生时向进程发送信号,对应的信号处理函数改变全局变量的值,信号处理函数返回后进程

    检测该全局变量,满足要求即可知道事件已发生。

    3、原理与第二种方法一致,不过使用的是函数sigsuspend

     

    示例1:

    //采用循环检测来判断事件的发生:

    #include <stdio.h>
    #include <sys/types.h>
    #include <signal.h>
    
    #define HAPPENED 1
    #define UNHAPPEN 0
    
    //定义全局变量以标识事件是否发生
    int flag_happen;
    
    void hand_sig(int sinno)
    {
        printf("recv SIGINT
    ");
        flag_happen = HAPPENED;
    }
    
    int main(int argc, char* argv[])
    {
    
        signal(SIGINT, hand_sig);
    
        while ( 1 )
        {
            if (HAPPENED == flag_happen)
            {
                printf("event happened
    ");
                break;
            }
        }
    
        return 0;
    }

     

     

    示例2:

    //pause挂起等待事件的发生

    #include <stdio.h>
    #include <sys/types.h>
    #include <signal.h>
    
    #define HAPPENED 1
    #define UNHAPPEN 0
    
    //定义全局变量以标识事件是否发生
    int flag_happen;
    
    void hand_sig(int sinno)
    {
        printf("recv SIGINT
    ");
        flag_happen = HAPPENED;
    }
    
    int main(int argc, char* argv[])
    {
    
        signal(SIGINT, hand_sig);
    
        while ( UNHAPPEN == flag_happen )
        {
            pause();
        }
    
        printf("after event happened
    ");
    
        return 0;
    }

     

    本程序存在一个潜在的bug:当信号发生在while之后,pause之前时,程序将检测不到事件的发生。此时,执行信号处理函数,flag_happen将被修改为

    HAPPENED,之后调用pause,而这时信号都已经被处理完了,自然pause将一直挂起,那么进程不会检测到此次事件的发生。

    示例3:

    使用sigsuspend函数挂起等待事件的发生。

    #include <stdio.h>
    #include <sys/types.h>
    #include <signal.h>
    
    #define HAPPENED 1
    #define UNHAPPEN 0
    
    //定义全局变量以标识事件是否发生
    int flag_happen;
    
    void hand_signal(int sinno)
    {
        printf("recv SIGINT
    ");
        flag_happen = HAPPENED;
    }
    
    int main(int argc, char* argv[])
    {
        flag_happen = UNHAPPEN;
    
        sigset_t newset, oldset, zeroset;
    
        signal(SIGINT, hand_signal);
    
        sigemptyset(&newset);
        sigemptyset(&oldset);
        sigemptyset(&zeroset);
    
        sigaddset(&newset, SIGINT);
    
        sigprocmask(SIG_BLOCK, &newset, &oldset);
        
        //临界区
        //使用sigsuspend取消所有信号的屏蔽并等待信号的触发
        while(UNHAPPEN == flag_happen)
        {
            sigsuspend(&zeroset);
        }
        
    
        //恢复信号屏蔽字
        sigprocmask(SIG_SETMASK, &oldset, NULL);
        
    
        return 0;
    }

    程序首先将SIGINT屏蔽,然后使用sigsuspend解除屏蔽,并挂起,等待事件的发生。

     

  • 相关阅读:
    linux添加超级用户
    MongDB配置方法
    【bzoj5174】[Jsoi2013]哈利波特与死亡圣器 二分+树形dp
    【bzoj3560】DZY Loves Math V 欧拉函数
    【bzoj5157】[Tjoi2014]上升子序列 树状数组
    【uoj#317】[NOI2017]游戏 2-SAT
    【bzoj5146】有趣的概率 微积分
    【bzoj4695】最假女选手 线段树区间最值操作
    【bzoj4355】Play with sequence 线段树区间最值操作
    【loj2319】[NOIP2017]列队 Splay(卡过)
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/6694004.html
Copyright © 2020-2023  润新知