• 信号处理signal、sigaction、pause、信号嵌套处理、不可重入函数


    信号的捕捉和处理

    主要由signal和sigaction函数来完成。还有一个函数pause,它可用来响应任何信号,不过不做任何处理。

    1、signal函数

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);

    当指定的信号到达时,就会跳转到参数handler指定的函数执行。如果handler参数不是函数指针,那么必须是常数:

    SIG_IGN(忽略该信号)或SIG_DFL(对该信号执行默认操作)。handler是一个函数指针。

    signal函数执行成功时返回以前的信号处理函数指针,当有错误发生时返回SIG_ERR(即 -1)

    注意:SIGKILL 和 SIGSTOP这两个信号不能被捕捉或忽略。

    2、sigaction函数:

    int sigaction(int signum, const struct sigaction *act, struct sigaction *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);
    };

    用来检查或设置进程在收到信号时的动作。

    参数signum可以是SIGKILL 和 SIGSTOP以外的任何信号。

    如果参数act不为空,则为signum设置新的信号处理函数;

    如果oldact不为空,则旧的信号处理函数将被存储在oldact中。

    sa_handler和sa_sigaction在某些体系结构上被定义为共同体,即这两个值在某一时刻只有一个有效。

    数据成员sa_restorer已经作废,不再使用,POSIX标准也不支持该数据成员。

    sa_handler可以是常数SIG_DFL 或 SIG_IGN,或者是一个信号处理函数的函数名。

    sa_sigaction也是用来指定信号signum的处理函数,但是它有3个参数,

    第一个参数是信号编号,

    第二个参数是一个指向siginfo_t 结构的指针,

    第三个参数是一个指向任何类型的指针,一般不使用。

    sa_mask成员变量声明了一个信号集,在调用信号捕捉函数之前,该信号集会增加到进程的信号屏蔽码中,新的信号屏蔽码会自动包括正在处理的信号(sa_flags

    未指定SA_NODEFER 或 SA_NOMASK)。

    当从信号捕捉函数返回时,进程的信号屏蔽码会恢复原来的值。因此,当处理一个给定的信号时,如果这种信号再次发生,那么会阻塞直到本次信号处理

    结束为止。若这种信号发生了多次,则对于不可靠信号,他只会阻塞一次,即本次信号处理结束以后只会再处理一次(相当于丢失了信号);对于可靠信号(实时信号),则会被阻塞多次,即

    信号不会丢失,信号发送了多少次就会调用信号处理函数多少次。

    sa_flags成员用来说明信号处理的一些其他相关操作,它可以取以下或他们的组合。

    ******

    *****

    ******

    SA_SIGINFO:如果设置了该标志,则信号处理函数由三参数的sa_sigaction指定而不是sa_handler指定。

     使用三参数的sa_sigaction来指定信号处理函数时,它的第二个参数可以用来传递数据,定义如下:

    接收信号的进程只能读取这些值,不能进行设置。si_int,si_ptr可以用来接收数据。

    ---------------------------------------------------------

    信号的嵌套处理:

    将sa_flags赋值为SA_NOMASK,即支持信号的嵌套处理。

    #include <stdio.h>
    #include <signal.h>
    
    int temp = 0;
    
    
    void sig_handler(int sig_num);
    
    
    int main()
    {
        struct sigaction act;
    
        act.sa_handler = sig_handler;
        act.sa_flags = SA_NOMASK;
    
        sigaction(SIGINT, &act, NULL);
        
        while(1);
    
    
        return 0;
    }
    
    void sig_handler(int sig_num)
    {
        printf("recv SIGINT
    ");
        sleep(5);
        temp+=1;
        printf("the value temp is:%d
    ", temp);
        printf("int sig_handler, after sleep
    ");
    
    }

    快速按下Ctrl+c组合键两次。

    执行说明:

    第一次按下Ctrl+c组合键发出SIGINT信号,休眠5秒。在5秒之内再次按下Ctrl+c组合键,由于我们设置了

    act.sa_flags = SA_NOMASK;

    因此程序又一次响应SIGINT信号,程序从sleep()处嵌套调用信号处理函数void sig_handler(int sig_num);再一次打印

    recv SIGINT 。休眠5秒之后,将temp的值打印出来并返回到本次信号处理函数的跳入点sleep处,然后再打印temp的值,并返回到主函数。

    从程序执行可以看到,temp的值随着信号处理函数被调用的次数的增加而递增,而由于实际应用中信号总是随机发生的,这样temp的值也会随机变化,

    如果main函数或其他地方还用到了这个全局变量,则程序将产生不可预料的结果。我们称这种数据会被破坏的函数为不可重入函数。

    编写信号处理函数时要注意不要使用不可重入函数。一般来说,满足下列条件之一的函数是不可重入的。

    (1)使用了静态的数据结构,如getgrgid(),全局变量等

    (2)函数实现时,调用了malloc或者free函数

    (3)函数实现时,调用了标准I/O函数

     

    3、pause函数:

    int pause(void);

    使调用进程挂起直至捕捉到一个信号。

    pause函数会令目前的进程进入睡眠状态,直到被信号所中断。该函数只返回-1并将errno设置为EINTR。

  • 相关阅读:
    总结下目前维护团队中用到的一些技术和工具
    一次修改时间导致的ORACLE 实例崩溃
    ruby 用watir 登录 CU的代码
    最近好烦.真的好烦
    Lucene.Net学习
    项目上线了,心情好爽
    轻松掌握XMLHttpRequest对象[转]
    微软发布3款SQL Injection攻击检测工具
    Domino开发
    用在JavaScript的RequestHelper [转]
  • 原文地址:https://www.cnblogs.com/zhangxuan/p/6612756.html
Copyright © 2020-2023  润新知