UNIX系统信号机制最简单的接口是signal函数。
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
返回值:若成功,返回以前的信号处理配置;若出错,返回SIG_ERR
signo参数如下。
func的值是常量SIG_IGN、SIG_DEF或当接到此信号后的调用的函数的地址。
如果指定SIG_IGN,则向内核表示忽略此信号。如果指定SIG_DEF,则表示接到此信号后的动作时系统默认的动作。当指定函数地址时,则在信号发生时,调用该函数,我们称这种处理为捕捉信号,称此函数为信号处理程序或信号捕捉函数。
signal函数原型说明此函数要求两个参数,返回一个函数指针,而该指针所指向的函数无返回值(void)。第一个参数signo是一个整型数,第一个参数是函数指针,它所指向的函数需要一个整型参数,无返回值。signal的返回值是一个函数地址,该函数有一个整型参数(即最后的(int))。用自然语言描述也就是要向信号处理程序传送一个整型参数,而它却无返回值。当调用signal设置信号处理程序时,第二个参数是指向该函数的指针。signal的但回执则是在此之前的信号处理程序的指针。
如果查看系统的头文件<signal.h>则很可能会找到下列形式的声明:
#define SIG_ERR (void (*)())-1
#define SIG_DEF (void (*)())0
#define SIG_IGN (void (*)())1
这些常量可用于表示“指向函数的指针,该函数要求一个整型参数,而且无返回值”。signal的第二个参数以其返回值就可用于他们表示。这些常量所使用的3个值不一定是-1、0、1,但它们必须是3个值而绝不能是任一函数的地址。
实例:
#include "apue.h"
static void sig_usr(int);
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)
{
if(signo == SIGUSR1)
printf("received SIGUSR1\n");
else if(signo == SIGUSR2)
printf("received SIGUSR2\n");
else
err_dump("received signal %d\n",signo);
}
我们使该进程在后台运行,并且用kill命令将信号发送给它,注意,在UNIX系统中,kill这个术语是不恰当的,kill命令知识将一个信号发送给一个进程组,该信号是否终止进程则是取决于该信号的类型,以及进程是否安排了捕捉该信号。
运行效果:
# ./a.out &
[1] 17952
# kill -USR1 17952
# received SIGUSR1
kill -USR2 17952
# received SIGUSR2
kill 17952
# ^C
[1]+ 已终止 ./a.out