zoukankan      html  css  js  c++  java
  • Linux 改进捕捉信号机制(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;
        int        sa_flags;//影响信号的行为SA_SIGINFO表示能接受数据
        void     (*sa_restorer)(void);//废弃
    };
    --第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中赢屏蔽掉哪些函数等等。
    --回调函数sa_handler、sa_sigaction只能任选其一
    //捕捉信号
    #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;
    }

  • 相关阅读:
    Java 之 Junit 单元测试
    数据结构和算法概述
    数组模拟队列
    单链表
    链表(Linked List)
    其它/编程 error201599
    SQL Server 生成 数据字典 / 数据库文档
    其它/编程 error2016420
    其它/编程 error2016118
    MySQL 数据 导入到 SQL Service
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5848005.html
Copyright © 2011-2022 走看看