linux中信号机制里面最简单的接口就是signal函数了。
原型如下:
#include<signal.h>
void ( * signal ( int signo , void ( * func ) ( int ) ) ) ( int ) ;
signo参数是信号名
func :(1)SIG_IGN 直接忽略
(2)SIG_DFL 系统默认处理方式
(3)捕捉函数的地址 用户捕捉(信号处理)
出错会返回SIG_ERR,
成功的时候返回值:指向之前的信号处理程序的指针(地址)
为了简化定义:
typedef void Sigfunc ( int ) ;
因此上面的定义可以写成:
Sigfunc * signal ( int , Sigfunc * );
同时一般进行如下声明:用常量来表示这种函数
#define SIG_ERR ((void (*)())) -1
#define SIG_DFL ((void (*)())) 0
#define SIG_IGN ((void (*)())) 1
一个使用signal函数的实例:
#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("recevied signal %d\n",signo);
}
}
$ ./a.out &
[1] 2945
$ kill -USR1 2945
received SIGUSR1
$ kill -USR2 2945
received SIGUSR2
$ kill 2945
[1]+ Terminated ./a.out
注意:由于这个程序补捕捉SIGTERM信号,而针对该信号的系统默认动作是终止,所以当向该进程发送SIGTERM信号时候,该进程会默认执行终止操作。
1)进程启动
signal函数的限制:
不改变信号的处理方式就不能确定信号的当前处理方式。(后面会提到sigaction函数能确定一个信号的处理方式,而不改变它)
很多捕捉中断和退出信号的处理方式的交互式程序,会有如下形式:
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);
2)进程创建
在一个进程使用fork函数创建子进程时候,其子进程继承父进程的信号处理方式。因为子进程在开始时候复制了父进程的存储映像,所以信号捕捉函数的地址在子进程中是有意义的。