• 信号之signal函数


    UNIX系统的信号机制最简单的接口是signal函数。signal函数的功能:为指定的信号安装一个新的信号处理函数。

    #include <signal.h>
    void (*signal(int signo, void (*func)(int)))(int);

    复杂原型分开看:

    void (* signal( int signo, void (*func)(int) )  )(int);

    函数名      :signal

    函数参数   :int signo, void (*func)(int)

    返回值类型:void (*)(int);

    signo参数是信号名(参见:http://www.cnblogs.com/nufangrensheng/p/3514157.html中UNIX系统信号Signal栏下的信号名)。func的值是常量SIG_IGN、常量SIG_DFL或当接到此信号后要调用的函数的地址。如果指定SIG_IGN,则向内核表示忽略此信号(记住有两个信号SIGKILL和SIGSTOP不能忽略)。如果指定SIG_DFL,则表示接到此信号后的动作是系统默认动作。当指定函数地址时,则在信号发生时,调用该函数,我们称这种处理为“捕捉”该信号。称此函数为信号处理程序(signal handler)或信号捕捉函数(signal-catching function)。

    signal的返回值是指向之前的信号处理程序的指针。(之前的信号处理程序,也就是在执行signal(signo,func)之前,对信号signo的信号处理程序)

    开头所示的signal函数原型太复杂了,如果使用下面的typedef,则可使其简单一些:

    typedef void Sigfunc(int);

    然后,可将signal函数原型写成:

    Sigfunc *signal(int,Sigfunc *);

    如果查看系统的头文件<signal.h>,则很可能会找到下列形式的声明:

    #define    SIG_ERR        ( void (*) () )-1
    #define    SIG_DFL        ( void (*) () )0
    #define    SIG_IGN        ( void (*) () )1

    这些常量可用于代替“指向函数的指针,该函数需要一个整型参数,而且无返回值”。signal的第二个参数及其返回值就可用它们表示。这些常量所使用的三个值不一定是-1,0和1。但大多数UNIX系统都使用上面所示的值。

    程序清单10-1 捕捉SIGUSR1和SIGUSR2的简单程序

    #include "apue.h"
    
    static void sig_usr(int);    /* one handler for both signals */
    
    int
    main(void)
    {
        if(signal(SIGUSR1, sig_usr) == SIG_ERR)
            err_sys("can't catch SIGUSR1");
        if(signal(SIGUSR2, sig_usr) == SIG_ERR)
            err_sys("can't catch SIGUSR2");
        for(;;)
            pause();
    }
    
    static void
    sig_usr(int signo)    /* argument is signal number */
    {
        if(signo == SIGUSR1)
            printf("received SIGUSR1
    ");
        else if (signo == SIGUSR2)
            printf("received SIGUSR2
    ");
        else
            err_dump("received signal %d
    ", signo);
    }

    pause函数,它使调用进程在接到一个信号前挂起。

    我们在后台运行该程序,并且用kill(1)命令将信号传送给它。注意,在UNIX中,杀死(kill)这个术语是不恰当的。kill(1)命令和kill(2)函数只是将一个信号送给一个进程或进程组。信号是否终止进程则取决于信号的类型,以及进程是否安排了捕捉该信号。

    未命名

    因为执行程序清单10-1的进程不捕捉SIGTERM信号,而针对该信号的系统默认动作是终止,所以当该进程发送SIGTERM信号后,该进程就会终止。

    1、程序启动

    当执行一个程序时,所有信号的状态都是系统默认或忽略。通常所有信号都被设置为它们的默认动作,除非调用exec的进程忽略该信号。确切地讲,exec函数将原先设置为要捕捉的信号都更改为它们的默认动作,其他信号的状态则不变(对于一个进程原先要捕捉的信号,当其执行一个新程序后,就自然不能再捕捉它了,因为信号捕捉函数的地址很可能在所执行的新程序文件中无意义)。

    一个具体的例子是一个交互式shell如何处理针对后台进程的中断和退出信号。对于一个非作业控制shell,当在后台执行一个进程时,例如:

    cc main.c &

    shell自动将后台进程中对中断和退出信号的处理方式设置为忽略。于是,当按中断键时就不会影响到后台进程。如果没有执行这样的处理,那么当按中断键时,它不但会终止前台进程,还会终止所有后台进程。

    很多捕捉这两个信号的交互式程序具有下列形式的代码:

    void sig_int(int), sig_quit(int);
    
    if(signal(SIGINT, SIG_IGN) != SIG_IGN)
        signal(SIGINT, sig_int);
    if(signal(SIGQUIT, SIG_IGN) != SIG_IGN)
        signal(SIGQUIT, sig_quit);

    这样处理后,仅当信号当前未被忽略时,进程才会捕捉它们。

    从signal的这两种调用中也可以看到这种函数的限制:不改变信号的处理方式就不能确定信号的当前处理方式

    2、进程创建

    当一个进程调用fork时,其子进程继承父进程的信号处理方式。因为子进程在开始时复制了父进程的存储映像,所以信号捕捉函数的地址在子进程中是有意义的。

    本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

  • 相关阅读:
    equals(),hashcode(),克隆学习心得
    AOP学习心得&jdk动态代理与cglib比较
    jackson注解使用心得
    rabbitmq使用心得
    web项目存数据到数据库,中文乱码,解决过程
    jdk动态代理学习
    团队作业——随堂小测(同学录)基本完工-紫仪
    alpha-咸鱼冲刺day3-紫仪
    alpha-咸鱼冲刺day2-紫仪
    alpha-咸鱼冲刺day1-紫仪
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3514547.html
Copyright © 2020-2023  润新知