zoukankan      html  css  js  c++  java
  • 信号—信号处理函数(捕捉)

    要明白信号处理函数的使用,就要先知道信号的捕捉设定,什么时候会调用信号处理函数和其执行的流程是什么,下图完整的展示了信号捕捉的设定,以及信号处理函数的触发机制: 

    所以,从上图可以知道,只有当程序中断,异常或系统调用,才会进入内核态,也只有进入了内核态才能处理信号,在这里初学者常常有一个误区,他们会觉得如果我在程序中没有设置中断、不出现异常、不使用系统调用,那就就不会进入内核态,也就不会处理信号了!这是对操作系统错误的理解,由于Linux是分时操作系统(但可以改成实时的如:UCOS就是linux修改而来的实时系统,很多人在此有误区),所以当时间片用完时,就会进入内核态,进行进程调度,在此就会处理信号了!
     内核给我们提供了一个用于注册用户自定义信号处理函数 的函数sigaction:

     1 #include <signal.h>
     2 
     3 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
     4 
     5 struct sigaction 定义:
     6 struct sigaction {
     7         void (*sa_handler)(int);
     8         void (*sa_sigaction)(int, siginfo_t *, void *);
     9         sigset_t sa_mask;
    10         int sa_flags;
    11         void (*sa_restorer)(void);
    12 };
    13 
    14 sa_handler :   早期的捕捉函数
    15 sa_sigaction : 新添加的捕捉函数,可以传参 , 和sa_handler互斥,两者通过sa_flags选择采用哪种捕捉函数
    16 sa_mask :  在执行捕捉函数时,设置阻塞其它信号,sa_mask | 进程阻塞信号集,退出捕捉函数后,还原回原有的阻塞信号集
    17           (即用于信号处理函数中是否还处理信号的到达)
    18 sa_flags : SA_SIGINFO 或者 0,上面两个函数调用哪一个,0调用sa_handler所指向的函数,1代表sa_sigaction所指向的函数
    19 sa_restorer : 保留,已过时

    所以我们要做的步骤是: 
    1)声明sigaction 结构体 
    2)构造sigaction 结构体 
    3)用sigaction 函数注册sigaction 结构体

     1 #include <stdio.h>
     2 #include <signal.h>
     3 
     4 /*
     5  * #include <signal.h>
     6  * int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
     7  * 
     8  * struct sigaction 定义:
     9  * struct sigaction {
    10  * void (*sa_handler)(int);
    11  * void (*sa_sigaction)(int, siginfo_t *, void *);
    12  * int sa_flags;  //上面两个函数调用哪一个,0调用最上面那个,1代表调用上面那
    13  * //在信号处理函数中的信号集,信号处理函数运行完之后就恢复原有信号集
    14  * sigset_t sa_mask;
    15  * void (*sa_restorer)(void);//现在已经废弃使用了
    16  *};
    17  */
    18 
    19 void do_sig(int num)
    20 {
    21     int n = 3;
    22     printf("i am do_sig
    ");
    23     while(n--)
    24     {
    25         printf("n = %d", n);
    26         sleep(1);
    27     }
    28     printf("num = %d
    ",num);
    29 }
    30 
    31 int main(void)
    32 {
    33 /*****************1.声明sigaction结构体****************/
    34     struct sigaction act;    
    35 /****************************************************/
    36 
    37 /*****************2.构造sigaction结构体****************/
    38     //标记信号处理函数
    39     //act.sa_handler = SIG_DFL;  //默认方式
    40     //act.sa_handler = SIG_IGN;  //忽略方式
    41     act.sa_handler = do_sig;     //捕捉方式,即指向信号处理函数
    42 
    43     //清空临时信号集,当信号处理函数结束时,信号集自动恢复
    44     sigemptyset(&act.sa_mask);
    45 
    46     //在临时信号集中屏蔽SIGQUIT信号,即在该信号处理函数中不会被SGIQUIT信号中断
    47     sigaddset(&act.sa_mask, SIGQUIT);
    48 
    49     act.sa_flags = 0;//调用哪一种,在上面的注释中有解释
    50 /****************************************************/
    51 
    52 /*****************3.注册sigaction结构体****************/
    53     //注册信号处理函数,当2号SIGINT信号到来时执行用户定义的信号处理函数
    54     sigaction(SIGINT, &act, NULL);
    55 /****************************************************/
    56 
    57     while(1)
    58     {
    59         printf("************************
    ");
    60         sleep(1);
    61     }
    62     return 0;
    63 }
    64 
    65 
    66 
    67 测试方法:
    68 运行该程序,按下Ctrl+c发送SIGINT信号,此时会进入用户定义的信号处理函数
    69 输出如下:
    70 ************************
    71 ************************
    72 ************************(按下Ctrl+c)
    73 i am do_sig
    74 n = 2n = 1n = 0num = 2
    75 ************************
    76 ************************
    77 ************************
    78 ************************(按下Ctrl+c)
    79 i am do_sig
    80 n = 2n = 1n = 0num = 2
    81 ************************
    82 ************************(按下Ctrl+退出程序)

    在开发过程中,我们往往不希望破坏linux原有的信号处理函数,所以内核也给我们提供了两个专门用于用户自定义的信号(10号信号SIGUSE1和12号信号SIGUSE2。 

     1 #include <stdio.h>
     2 #include <signal.h>
     3 
     4 void do_sig(int num)
     5 {
     6     printf("i am do_sig
    ");
     7     printf("num = %d
    ",num);
     8 }
     9 
    10 int main(void)
    11 {
    12     struct sigaction act;
    13     act.sa_handler = do_sig;
    14     sigemptyset(&act.sa_mask);
    15     sigaddset(&act.sa_mask, SIGQUIT);
    16     act.sa_flags = 0;
    17 
    18     //注册信号处理函数
    19     sigaction(SIGUSR1, &act, NULL);
    20 
    21     while(1)
    22     {
    23         printf("************************
    ");
    24         sleep(1);
    25     }
    26     return 0;
    27 }
    28 
    29 
    30 测试方法:
    31 在一个终端中运行该程序(此时在该终端中会一直输出:********************32 在另一终端中输入ps -aux命令查询运行该程序的进程id号
    33 并输入kill -10 进程id号   向该程序发送10号消息SIGUSR1
    34 此时运行该程序的终端中会输出:i am do_sig
    35                           num = 10

     

     另一方面,c库函数也为我们提供了一个封装更高层,接口更简单的函数signal

    1 include <signal.h>
    2 
    3 typedef void (*sighandler_t)(int)
    4 sighandler_t signal(int signum, sighandler_t handler)
    #include <stdio.h>
    #include <signal.h>
    
    void do_sig(int n)
    {
        printf("hello
    ");
    }
    
    int main(void)
    {
        signal(SIGINT, do_sig);
    
        while(1)
        {
            printf("****************************
    ");
            sleep(1);
        }
        return 0;
    }
    运行后按Ctrl+c即可查看效果,若要关闭程序则按Ctrl+

  • 相关阅读:
    python函数执行超时处理的两种方法
    Flask常用方法函数汇总
    夜神模拟器操作
    简单auto.js自动化处理andorid手机案例
    TCP-三次握手和四次挥手简单概述
    android手机执行shell脚本
    接口测试要测试什么?怎么测?
    python unittest单元测试
    python webdriver 测试框架--数据驱动之Excel驱动
    顺时针打印矩阵
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/6408108.html
Copyright © 2011-2022 走看看