• sigaction和实时信号sigqueue


    sigaction函数
    sigaction函数的功能是用于改变进程接收到特定信号后的行为。
    int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
    参数
    --第一个参数是信号的值,可以为除了SIGKILL及SIGSTOP外的任何一个特定有效的信号(因为这两个信号定义了自己的处理函数,将导致信号安装错误)
    --第二个参数是指向节后sigaction的一个实例的指针,在sigaction的实例中,指定了对特定信号的处理,可以为NULL,进程会以缺省方式对信号处理
    --第三个参数oldact指向的对象用来保存原来对相应信号的处理,可以为NULL
    返回值:函数成功返回0,失败返回-1。

    sigaction函数检查或修改与指定信号相关联的处理动作,该函数取代了signal函数。
    因为signal函数在信号未决时接收信号可能出现问题,所以使用sigaction更安全。
    sigaction结构体
    struct sigaction {
        void     (*sa_handler)(int);//信号处理程序 不接受额外数据
        void     (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能接受额外数据,可以和sigqueue配合使用
        sigset_t   sa_mask;

    //sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下当前信号本身被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位。注:请注意sa_mask指定的信号阻塞的前提条件,是在由sigaction()安装信号的处理函数执行过程中由sa_mask指定的信号才被阻塞。

        int        sa_flags;//影响信号的行为SA_SIGINFO表示能接受数据
        void     (*sa_restorer)(void);//废弃
    };
    --第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中赢屏蔽掉哪些函数等等。
    --回调函数sa_handler、sa_sigaction只能任选其一

    /** @file  signalT.cpp
    *  @note  
    *  @brief
    *  @author xor
    *  @date   2019-7-20
    *  @history
    *  @warning
    */
    //捕捉信号
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <signal.h>
    
    void catch_signal(int sign)
    {
        switch(sign)
        {
        case SIGINT:
            //SIGINT默认行为是退出进程
            printf("SIGINT signal
    ");
            exit(0);
            break;
        case SIGALRM:
            //SIGALRM默认行为是退出进程
            printf("SIGALRM signal
    ");
            break;
        case SIGKILL:
            printf("SIGKILL signal
    ");
            break;
        }
    }
    
    //建议使用封装之后的mysignal
    int mysignal(int sign,void (*func)(int))
    {
        struct sigaction act,oact;
        //传入回调函数
        act.sa_handler=func;
        //将act的属性sa_mask设置一个初始值
        sigemptyset(&act.sa_mask);
        act.sa_flags=0;
        return sigaction(sign,&act,&oact);
    }
    
    int main(int arg, char *args[])
    {
        mysignal(SIGINT,catch_signal);
        mysignal(SIGALRM,catch_signal);
        mysignal(SIGKILL,catch_signal);
        int i=0;
        while(1)
        {
            printf("hello god  %d
    ",i++);
            sleep(1);
        }
        return 0;
    }

    sigqueue函数
    --新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与sigaction()函数配合使用
    --注意:和kill函数相比int kill(pid_t pid,int signo)多了参数
    --原型 int sigqueue(pid_t pid,int signo,const union sigval value);
    --参数 sigqueue的第一个参数是指定接收信号的进程pid,第二个参数确定即将发送的信号,
    第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。
    --函数成功返回0,失败返回-1,并且更新errno
    --sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组
    --union sigval联合体
    typedef union sigval
    {
    int sival_int;
    void * sival_ptr;
    }sigval_t;

    #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>
    /*
     siginfo_t {
                   int      si_signo;    // Signal number
                   int      si_errno;    // An errno value
                   int      si_code;     // Signal code
                   int      si_trapno;   // Trap number that caused
                                            hardware-generated signal
                                            (unused on most architectures)
                   pid_t    si_pid;      // Sending process ID
                   uid_t    si_uid;      // Real user ID of sending process
                   int      si_status;   // Exit value or signal
                   clock_t  si_utime;    // User time consumed
                   clock_t  si_stime;    // System time consumed
                   sigval_t si_value;    // Signal value
                   int      si_int;      // POSIX.1b signal
                   void    *si_ptr;      // POSIX.1b signal
                   int      si_overrun;  // Timer overrun count; POSIX.1b timers
                   int      si_timerid;  // Timer ID; POSIX.1b timers
                   void    *si_addr;     // Memory location which caused fault
                   int      si_band;     // Band event
                   int      si_fd;       // File descriptor
               }
    
               */
    
    void catch_signal(int signo,siginfo_t *resdata,void *unkonwp)
    {
        printf("signo=%d
    ",signo);
        printf("return data :%d
    ",resdata->si_value.sival_int);
        printf("second return data:%d
    ",resdata->si_int);
        return ;
    }
    
    int main(int arg, char *args[])
    {
        pid_t pid=0;
        pid=fork();
        if(pid==-1)
        {
            printf("fork() failed! error message:%s
    ",strerror(errno));
            return -1;
        }
        if(pid==0)
        {
            printf("i am child!
    ");
            //等待父进程执行完信号安装
            sleep(5);
            //向父进程发送带数据的信号
            union sigval sigvalue;
            sigvalue.sival_int=222;
            //发送信号
            if(sigqueue(getppid(),SIGINT,sigvalue)==-1)
            {
                printf("sigqueue() failed ! error message:%s
    ",strerror(errno));
                exit(0);
            }
            printf("子进程信号发送成功!
    ");
            exit(0);
        }
        if(pid>0)
        {
            printf("i am father!
    ");
            //安装信号
            struct sigaction act;
            //初始化sa_mask
            sigemptyset(&act.sa_mask);
            act.sa_sigaction=catch_signal;
            //一旦使用了sa_sigaction属性,那么必须设置sa_flags属性的值为SA_SIGINFO
            act.sa_flags=SA_SIGINFO;
            //安装信号
            if(sigaction(SIGINT,&act,NULL)!=0)
            {
                printf("sigaction() failed! 
    ");
                return -1;
            }
            //等待子进程返回
            int status=0;
            wait(&status);
            printf("game over!
    ");
        }
        return 0;
    }
    实时信号支持排队不会丢失。(实时信号还有一个特点,即到达的顺序是可以保证的)
  • 相关阅读:
    白帽子 攻防
    自定义WCF的配置文件
    .net快速创建PDF文档 by c#
    如何在面试中发现优秀程序员
    kafka-java客户端连接
    xshell 登陆堡垒机实现自动跳转
    良好的编程习惯
    Mycat-介绍
    scala-传名函数和传值函数
    springboot-31-springboot静态注入
  • 原文地址:https://www.cnblogs.com/guxuanqing/p/11218636.html
Copyright © 2020-2023  润新知