美文网首页Linux
信号处理函数

信号处理函数

作者: 小叶大孟 | 来源:发表于2018-05-02 17:58 被阅读0次

    信号处理函数

    sigaction的用法

    int sigaction (

            int signo,

            const struct sigaction *act,

            struct sigaction *oldact

    );

    这个函数主要是用于改变或检测信号的行为。

    第一个参数是变更signo指定的信号,它可以指向任何值,SIGKILL,SIGSTOP除外

    第二个参数,第三个参数是对信号进行细粒度的控制。

    如果*act不为空,*oldact不为空,那么oldact将会存储信号以前的行为。

    如果act为空,*oldact不为空,那么oldact将会存储信号现在的行为。

    struct sigaction  {

            void (*sa_handler)(int);

            void (*sa_sigaction)(int, siginfo_t*, void*);

            sigset_t sa_mask;

            int sa_flags;

            void (*sa_restorer)(void);

    }

    参数含义:

    sa_handler是一个函数指针,主要是表示接收到信号时所要采取的行动。此字段的值可以是SIG_DFL,SIG_IGN.分别代表默认操作与内核将忽略进程的信号。这个函数只传递一个参数那就是信号代码。

    当SA_SIGINFO被设定在sa_flags中,那么则会使用sa_sigaction来指示信号处理函数,而非sa_handler.

    sa_mask设置了掩码集,在程序执行期间会阻挡掩码集中的信号。

    sa_flags设置了一些标志, SA_RESETHAND当该函数处理完成之后,设定为为系统默认的处理模式。SA_NODEFER 在处理函数中,如果再次到达此信号时,将不会阻塞。默认情况下,同一信号两次到达时,如果此时处于信号处理程序中,那么此信号将会阻塞。

    SA_SIGINFO表示用sa_sigaction指示的函数。

    sa_restorer已经被废弃。

    sa_sigaction所指向的函数原型:

    void my_handler(int signo, siginfo_t *si, void *ucontext);

    第一个参数: 信号编号

    第二个参数:指向一个siginfo_t结构。

    第三个参数是一个ucontext_t结构。

    其中siginfo_t结构体中包含了大量的信号携带信息,可以看出,这个函数比sa_handler要强大,因为前者只能传递一个信号代码,而后者可以传递siginfo_t信息。

    typedef struct siginfo_t {

            int si_signo;//信号编号

            int si_errno;//如果为非零值则错误代码与之关联

            int si_code;//说明进程如何接收信号以及从何处收到

            pid_t si_pid;//适用于SIGCHLD,代表被终止进程的PID

            pid_t si_uid;//适用于SIGCHLD,代表被终止进程所拥有进程的UID

            int si_status;//适用于SIGCHLD,代表被终止进程的状态

            clock_t si_utime;//适用于SIGCHLD,代表被终止进程所消耗的用户时间

            clock_t si_stime;//适用于SIGCHLD,代表被终止进程所消耗系统的时间

            sigval_t si_value;

            int si_int;

            void * si_ptr;

            void* si_addr;

            int si_band;

            int si_fd;

    };

    sigqueue的用法

    sigqueue( pid_t pid, int signo, const union sigval value)

    union sigval  {int sival_int, void*sival_ptr };

    sigqueue函数类似于kill,也是一个进程向另外一个进程发送信号的。

    但它比kill函数强大。

    第一个参数指定目标进程的pid.

    第二个参数是一个信号代码。

    第三个参数是一个共用体,每次只能使用一个,用来进程发送信号传递的数据。

    或者传递整形数据,或者是传递指针。

    发送的数据被sa_sigaction所指示的函数的siginfo_t结构体中的si_ptr或者是si_int所接收。

    sigpending的用法

    sigpending(sigset_t set);

    这个函数的作用是返回未决的信号到信号集set中。

    即未决信号集,未决信号集不仅包括被阻塞的信号,也可能包括已经到达但没有被处理的信号。

    示例1: sigaction函数的用法

    void signal_set1(int x) { //信号处理函数,只传递一个参数信号代码

            printf("xxxxx/n");

            while(1)  {

                    //

             }

    }

    void signal_set(struct sigaction *act)

    {

            switch(act->sa_flags) {

            case (int)SIG_DFL:

                    printf("using default hander/n");

                    break;

            case (int)SIG_IGN:

                    printf("ignore the signal/n");

                    break;

            default:

                    printf("%0x/n",act->sa_handler);

            }

    }

    int main(int argc, char** argv)

    {

            int i;

            struct sigaction act,oldact;

            act.sa_handler = signal_set1;

            act.sa_flags = SA_RESETHAND;

            //SA_RESETHANDD 在处理完信号之后,将信号恢复成默认处理

            //SA_NODEFER在信号处理程序执行期间仍然可以接收信号

            sigaction (SIGINT,&act,&oldact) ;//改变信号的处理模式

            for (i=1; i<12; i++)

            {

                    printf("signal %d handler is : ",i);

                    sigaction (i,NULL,&oldact) ;

                    signal_set(&oldact);//如果act为NULL,oldact会存储信号当前的行为

                    //act不为空,oldact不为空,则oldact会存储信号以前的处理模式

            }

            while(1) {

                    //等待信号的到来

            }

            return 0;

    }

    运行结果:

    [root@localhost C]# ./s2

    signal 1 handler is : using default hander

    signal 2 handler is : 8048437

    signal 3 handler is : using default hander

    signal 4 handler is : using default hander

    signal 5 handler is : using default hander

    signal 6 handler is : using default hander

    signal 7 handler is : using default hander

    signal 8 handler is : using default hander

    signal 9 handler is : using default hander

    signal 10 handler is : using default hander

    signal 11 handler is : using default hander

    xxxxx

    解释:

    sigaction(i,NULL,&oldact);

    signal_set(&oldact);

    由于act为NULL,那么oldact保存的是当前信号的行为,当前的第二个信号的行为是执行自定义的处理程序。

    当按下CTRL+C时会执行信号处理程序,输出xxxxxx,再按一下CTRL+C会停止,是由于SA_RESETHAND恢复成默认的处理模式,即终止程序。

    如果没有设置SA_NODEFER,那么在处理函数执行过程中按一下CTRL+C将会被阻塞,那么程序会停在那里。

    示例2: sigqueue向本进程发送数据的信号

    void myhandler(int signo, siginfo_t *si, void *ucontext);

    int main()  {

            union sigval val;//定义一个携带数据的共用体

            struct sigaction oldact,act;

            act.sa_sigaction = myhandler;

            act.sa_flags = SA_SIGINFO;//表示使用sa_sigaction指示的函数,处理完恢复默认,不阻塞处理过程中到达下在被处理的信号

            //注册信号处理函数

            sigaction(SIGUSR1, &act, &oldact);

            char data[100];

            int num=0;

            while( num < 10 )  {

                    sleep( 2 );

                    printf("等待SIGUSR1信号的到来/n");

                    sprintf(data, "%d", num++);

                    val.sival_ptr=data;

                    sigqueue( getpid(), SIGUSR1, val );//向本进程发送一个信号

                }

    }

    void myhandler ( int signo, siginfo_t *si, void *ucontext )  {

            printf("已经收到SIGUSR1信号/n");

            printf("%s/n",(char*)(si->si_ptr));

    }

    程序执行的结果是:

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    0

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    1

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    2

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    3

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    4

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    5

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    6

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    7

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    8

    等待SIGUSR1信号的到来

    已经收到SIGUSR1信号

    9

    解释: 

    本程序用sigqueue不停的向自身发送信号,并且携带数据,数据被放到处理函数的第二个参数siginfo_t结构体中的si_ptr指针,当num<10时不再发。

    一般而言,sigqueue与sigaction配合使用,而kill与signal配合使用。

    示例3: 一个进程向另外一个进程发送信号,并携带信息

    发送端:

    int main()  {

            union sigval value;

            value.sival_int=10;

            if ( sigqueue(4403, SIGUSR1, value) == -1 )  {  //4403是目标进程pid

                    perror("信号发送失败/n");

            }

            sleep(2);

    }

    接收端:

    void myhandler ( int signo, siginfo_t*si, void *ucontext );

    int main () {

            struct sigaction oldact, act;

            act.sa_sigaction = myhandler;

            act.sa_flags = SA_SIGINFO | SA_NODEFER;

            //表示执行后恢复,用sa_sigaction指示的处理函数,在执行期间仍然可以接收信号

            sigaction ( SIGUSR1, &act, &oldact );

            while ( 1 )  {

                    sleep ( 2 );

                    printf("等待信号的到来/n");

            }

    }

    void myhandler ( int signo, siginfo_t *si, void *ucontext ) {

            printf("the value is %d/n",si->si_int);

    }

    示例4: sigpending的用法

    sigpending (sigset_t *set )将未决信号放到指定的set信号集中去,未决信号包括被阻塞的信号和信号到达时但还没来得及处理的信号

    void myhandler ( int signo, siginfo_t *si, void *ucontext );

    int main()  {

            struct sigaction oldact, act;

            sigset_t oldmask, newmask, pendingmask;

            act.sa_sigaction = myhandler;

            act.sa_flags = SA_SIGINFO;

            sigemptyset( &act.sa_mask );  //首先将阻塞集合设置为空,即不阻塞任何信号

            //注册信号处理函数

            sigaction(SIGRTMIN + 10, &act ,&oldact);

            //开始阻塞

            sigemptyset( &newmask );

            sigaddset( &newmask, SIGRTMIN + 10);

            printf("SIGRTMIN + 10 blocked/n");

            sigprocmask( SIG_BLOCK , &newmask ,&oldmask );

            sleep(20);  //为了发出信号

            printf("now begin to get pending mask/n");

            if ( sigpending( &pendingmask ) < 0 )  {

                    perror("pendingmask error");

            }

            if ( sigismember( &pendingmask, SIGRTMIN + 10 ) )  {

                    printf("SIGRTMIN+10 is in the pending mask/n");

            }

            sigprocmask( SIG_UNBLOCK, &newmask, &oldmask);

            printf("SIGRTMIN+10 unblocked/n");

    }

    //信号处理函数

    void myhandler ( int signo, siginfo_t *si, void *ucontext )  {

            printf("receive signal %d/n",si->si_signo);

    }

    程序执行:

    在另一个shell发送信号:

    kill -44 4579

    SIGRTMIN +10 blocked

    now begin to get pending mask

    SIGRTMIN +10 is in the pending mask

    receive signal 44

    SIGRTMIN +10 unblocked

    可以看到SIGRTMIN由于被阻塞所以处于未决信号集中。

    相关文章

      网友评论

        本文标题:信号处理函数

        本文链接:https://www.haomeiwen.com/subject/wkwcrftx.html