一、signal函数概述
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);

返回值:

  • 成功:返回一个函数指针,该指针所指向的函数无返回值(void)。返回值是上一次调用signal函数传入的函数指针。如果是第一次调用signal函数,那么返回SIG_DEF
  • 出错:返回常量SIG_ERR(-1),并设置errno

参数:

  • 第一个参数:signo是一个整型数
  • 第二个参数:
    • 可以是信号处理函数
    • 可以是后面两个宏定义。常数SIG_IGN(向内核表示忽略此信号)或是常数SIG_DFL(表示接到此信号后的动作是系统默认动作)
    • 处理函数无返回值,且以参数1位参数

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

  • typedef  void  Sigfunc(int);
  • 然后,可将signal函数原型写成: Sigfunc   *signal(int, Sigfunc *);
  • 如果查看系统的头文件#include<signal.h>, 则可能会找到下列形式的说明:
#define SIG_ERR (void (*)()) -1
#define SIG_DFL (void (*)()) 0
#define SIG_IGN (void (*)()) 1
  • 这些常数可用于表示“指向函数的指针,该函数要一个整型参数,而且无返回值”。signal的第二个参数及其返回值就可用它们表示。这些常数所使用的三个值不一定要是-1,0和1
二、使用sigaction代替signal函数
  • signal函数是由ISO C定义的。因为ISO C不涉及多进程、进程组以及终端I/O等,所以它对信号的定义非常含糊,以致于对UNIX系统而言几乎毫无用处
  • 从UNIX System V派生的实现支持signal函数,但该函数提供旧的不可靠信号语义。提供此函数主要是为了向后兼容要求此旧语义的应用程序,新应用程序不应使用这些不可靠信号
  • 4.4BSD也提供signal函数,但它是按照sigaction函数定义的,所以在4.4BSD之下使用提供新的可靠信号语义。目前大多数系统遵循这种策略,但Solaris 10沿用System V signal函数的语义
  • 因为signal的语义与实现有关,所以最好使用sigaction函数替代signal函数。在sigaction函数的文章中,提供了使用该函数的signal的一个实现。因此,为了增加平台之间的移植性,最好都是用我们定义的这个signal函数(sigaction函数介绍见文章:javascript:void(0)
三、案例
  • pause函数,它使调用进程睡眠(挂起)
#include<signal.h>
#include<stdio.h>
#include <unistd.h>
static void sig_usr(int);

int main(void)
{
    if (signal(SIGUSR1, sig_usr) == SIG_ERR)
        perror("can’t catch SIGUSR1");
    if (signal(SIGUSR2, sig_usr) == SIG_ERR)
        perror("can’t catch SIGUSR2");
    for (;;)
        pause();
}

static void sig_usr(int signo)
{
    if (signo == SIGUSR1)
        printf("received SIGUSR1\n");
    else if (signo == SIGUSR2)
        printf("received SIGUSR2\n");
    else
        printf("received signal %d\n", signo);
}

演示结果

  • kill -USR1 2325:向进程发送SIGUSR1信号
  • kill -USR2 2325:向进程发送SIGUSR2信号
  • kill 2325:向进程发送SIGTREM(因为该进程没有设置该信号捕获函数,所以使用默认动作终止程序)

APUE编程:71---信号处理(signal信号捕获函数)_#define