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\n");
        exit(0);
        break;
    case SIGALRM:
        //SIGALRM默認行為是退出進程
        printf("SIGALRM signal\n");
        break;
    case SIGKILL:
        printf("SIGKILL signal\n");
        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\n",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\n",signo);
    printf("return data :%d\n",resdata->si_value.sival_int);
    printf("second return data:%d\n",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\n",strerror(errno));
        return -1;
    }
    if(pid==0)
    {
        printf("i am child!\n");
        //等待父進程執行完信號安裝
        sleep(5);
        //向父進程發送帶數據的信號
        union sigval sigvalue;
        sigvalue.sival_int=222;
        //發送信號
        if(sigqueue(getppid(),SIGINT,sigvalue)==-1)
        {
            printf("sigqueue() failed ! error message:%s\n",strerror(errno));
            exit(0);
        }
        printf("子進程信號發送成功!\n");
        exit(0);
    }
    if(pid>0)
    {
        printf("i am father!\n");
        //安裝信號
        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! \n");
            return -1;
        }
        //等待子進程返回
        int status=0;
        wait(&status);
        printf("game over!\n");
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM