C陷阱与缺陷 第5章 库函数 5.5 库函数signal

发布于:2022-12-25 ⋅ 阅读:(359) ⋅ 点赞:(0)

    实际上所有的C语言实现中都包括signal库函数,将其作为捕获异步事件的一种方式。
    要调用该库函数,需要在源文件中加上: 
     #include <signal.h>
    以引入相关的声明。要处理一个特定的signal(信号),可以这样调用signal函数: 
    signal(signal type, handler function);
    signal type代表系统头文件signal.h中定义的某些变量,这些常量用来标识signal函数将要捕获的信号类型。handler function是当指定的事件发生时,将要加以调用的事件处理函数。

    在许多C语言实现中,信号是真正意义上的“异步”。从理论上说,一个信号可能在C程序执行期间的任何时刻发生。需要特别强调的是,信号甚至可能出现在某些复杂库函数(如malloc)的执行过程中。因此,从安全的角度考虑,信号的处理函数不应该调用上述类型的库函数。例如,假设malloc函数的执行过程被一个信号中断。此时,malloc函数可以用来跟踪内存的数据结构很可能部分被更新,如果signal处理函数再调用malloc函数,结果可能是malloc函数用到的数据结构完全崩溃,后果不堪设想!

    基于同样的原因,从signal处理函数中使用longjmp退出,通常情况下也是不安全的:因为信号可能发生在malloc或者其他库函数开始更新某个数据结构,但又没有最后完成的过程中。因此,signal处理函数能够做的安全的事情,似乎就只有设置一个标志然后返回,期待以后主程序能够检查这个标志,发现一个信号已经发生。
    然而,就算这样做也并不总是安全的。当一个算术运算错误(例如溢出或者零作除数)引发一个信号时,某些机器在signal处理函数返回后还将重新执行失败的操作。而当这个算术运算重新执行时,我们并没有一个可移植的办法来改变操作数。在这种情况下,最可能的结果就是马上又引发一个同样的信号。因此,对于算术运算错误,signal处理函数的唯一安全、可移植的操作就是打印一条出错信息,然后使用longjmp或exit立即退出程序。
    我们得到的结果是:信号非常复杂棘手,而且具有一些从本质上而言不可移植的特性。要解决这个问题,我们最好采取“守势”,让signal处理函数尽可能简单,并将它们组织在一起。这样,当需要适应一个新系统时,我们可以很容易进行修改。 

    /*
    ** signal。 
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <setjmp.h>

    jmp_buf restart;

    void handler( int );
 
    int main( void ){
        int a, b;
        int quot;
        int result;
    
        signal( SIGFPE, handler );
        a = 7;
        b = 0;
        result = setjmp( restart );
        if( result == 0 ){
            quot = a / b;
            printf( "a = %d, b = %d, quot = %d\n", a, b, quot );
        } else{
            printf( "divisor can't be zero!\n" );
            printf( "a = %d, b = %d\n", a, b );
        }
 
        return EXIT_SUCCESS;
    }

    void handler( int sig ){
        /*
        if( sig == SIGFPE ){
            printf( "an arithmetric error happens!\n" );
            exit( EXIT_FAILURE );
        }
        */
        if( sig == SIGFPE ){
            printf( "an arithmetric error happens!\n" );
            longjmp( restart, 1 );
        }
    }
输出:

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到