一、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函数介绍见文章:https://blog.csdn.net/qq_41453285/article/details/89278415)
三、案例
- 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(因为该进程没有设置该信号捕获函数,所以使用默认动作终止程序)