设置信号信号处理函数void (*signal (int signo ,void (*fun)(int )))(int)
一个进程收到信号时需要跳转到信号处理函数的代码处执行。系统为每个信号提供给了多种默认的处理方式。
linux允许用户提供自己的信号处理函数,使用signal函数将处理函数加载,并且通知系统.
函数原型:
#include<signal.h>
void (*signal (int signo ,void (*fun)(int )))(int)
函数原型各参数详细解释
(一)signal函数的第一个参数是需要加载处理的信号编号,例如
SIGKILL等,该编号是一个宏,其本质是一个整数,定义在signal.h文件中
(二)第二个参数是一个函数指针,这个函数捕捉到第一个函数指定的信号,并对其进行处理,该参数可以是以下三个值中的一个
1)SIG_IGN:表示忽略该信号,即捕捉到信号后不做任何处理,该宏定义在signal.h文件中
#define SIG_IGN ((void *)(*)())1
2)SIG_DFL表示使用默认的信号处理方式,这样可以对此信号恢复系统的默认处理方式,该宏定义在signal.h文件中
#define SIG_DFL ((void *)(*)())0
3)其他已定义的函数指针:表示使用用户自己的处理函数处理此信号,
该信号成为信号处理函数,信号处理函数的原型为:void handler(int);
signal函数的返回值也是一个函数指针,这个函数指向上一次的信号处理程序,因此这个函数和signal的第二个参数所表示的的参数原型一致
,如果出错,signal函数返回SIG_ERR ,该宏定义在signal.h文件中
的多个信号可以共用一个处理程序,处理程序内部的流程只需要根据参数来判断即可了。
信号处理函数如下:
void handler( int signo )
{
switch(signo)
{
case SIGUSR1:
......
case SIGUSR2:
......
......
case SIGUSRn:
......
}
}
下面的程序展示了父子进程使用SIGUSR1和SIGUSR2进行通信
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void handler( int signo )
{
switch(signo)
{
case SIGUSR1:
printf("parent :catch SIGUSR1\n");break;
case SIGUSR2:
printf("child :catch SIGUSR2\n");break;
default :
printf("should not be here\n");break;
}
return ;
}
int main( void )
{
pid_t ppid, cpid ;
/*为两个进程设置信号处理函数*/
if( signal(SIGUSR1, handler)== SIG_ERR)//设置出错
{
perror("can`t set handle for SIGUSR1");
exit(1);
}
if( signal(SIGUSR2, handler)== SIG_ERR)//设置出错
{
perror("can`t set handle for SIGUSR2");
exit(1);
}
ppid = getpid();//得到父进程id
if((cpid = fork() )< 0 )//创建子进程
{
perror("fail to fork");
exit(1);
}
else if(cpid == 0)
{//子进程向父进程发送SIGUSR1信号
if(kill(ppid,SIGUSR1)== -1)
{
perror("fail to send signal");
exit(1);
}
while(1);//死循环,等待父进程的信号
}
else
{
sleep(1);//休眠,保证子进程先运行,并且发送SIGUSR1信号
//向子进程发送SIGUSR2信号
if(kill(cpid,SIGUSR2) == -1)
{
perror("fail to send signal");
exit(1);
}
printf("kill child\n");//输出提示信息
if(kill(cpid,SIGKILL)== -1)//发送SIGKILL信号杀死子进程
{
perror("fail to send signal");
exit(1);
}
if(wait(NULL) == -1 )//回收子进程状态,避免僵尸进程
{
perror("fail to wait");
exit(1);
}
}
return 0;
}
一个进程收到信号时需要跳转到信号处理函数的代码处执行。系统为每个信号提供给了多种默认的处理方式。
linux允许用户提供自己的信号处理函数,使用signal函数将处理函数加载,并且通知系统.
函数原型:
#include<signal.h>
void (*signal (int signo ,void (*fun)(int )))(int)
函数原型各参数详细解释
(一)signal函数的第一个参数是需要加载处理的信号编号,例如
SIGKILL等,该编号是一个宏,其本质是一个整数,定义在signal.h文件中
(二)第二个参数是一个函数指针,这个函数捕捉到第一个函数指定的信号,并对其进行处理,该参数可以是以下三个值中的一个
1)SIG_IGN:表示忽略该信号,即捕捉到信号后不做任何处理,该宏定义在signal.h文件中
#define SIG_IGN ((void *)(*)())1
2)SIG_DFL表示使用默认的信号处理方式,这样可以对此信号恢复系统的默认处理方式,该宏定义在signal.h文件中
#define SIG_DFL ((void *)(*)())0
3)其他已定义的函数指针:表示使用用户自己的处理函数处理此信号,
该信号成为信号处理函数,信号处理函数的原型为:void handler(int);
signal函数的返回值也是一个函数指针,这个函数指向上一次的信号处理程序,因此这个函数和signal的第二个参数所表示的的参数原型一致
,如果出错,signal函数返回SIG_ERR ,该宏定义在signal.h文件中
#define SIG_ERR (void (*)())-1
信号是异步的通信方式,其到来由系统通知应用程序,所以信号处理函数是由系统调用的,其参数表示当前所捕捉到的信号的编号,也就是说该参数其实和signal的第一个参数signal是等效的。这样的好处是多余的多个信号可以共用一个处理程序,处理程序内部的流程只需要根据参数来判断即可了。
信号处理函数如下:
void handler( int signo )
{
switch(signo)
{
case SIGUSR1:
......
case SIGUSR2:
......
......
case SIGUSRn:
......
}
}
下面的程序展示了父子进程使用SIGUSR1和SIGUSR2进行通信
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void handler( int signo )
{
switch(signo)
{
case SIGUSR1:
printf("parent :catch SIGUSR1\n");break;
case SIGUSR2:
printf("child :catch SIGUSR2\n");break;
default :
printf("should not be here\n");break;
}
return ;
}
int main( void )
{
pid_t ppid, cpid ;
/*为两个进程设置信号处理函数*/
if( signal(SIGUSR1, handler)== SIG_ERR)//设置出错
{
perror("can`t set handle for SIGUSR1");
exit(1);
}
if( signal(SIGUSR2, handler)== SIG_ERR)//设置出错
{
perror("can`t set handle for SIGUSR2");
exit(1);
}
ppid = getpid();//得到父进程id
if((cpid = fork() )< 0 )//创建子进程
{
perror("fail to fork");
exit(1);
}
else if(cpid == 0)
{//子进程向父进程发送SIGUSR1信号
if(kill(ppid,SIGUSR1)== -1)
{
perror("fail to send signal");
exit(1);
}
while(1);//死循环,等待父进程的信号
}
else
{
sleep(1);//休眠,保证子进程先运行,并且发送SIGUSR1信号
//向子进程发送SIGUSR2信号
if(kill(cpid,SIGUSR2) == -1)
{
perror("fail to send signal");
exit(1);
}
printf("kill child\n");//输出提示信息
if(kill(cpid,SIGKILL)== -1)//发送SIGKILL信号杀死子进程
{
perror("fail to send signal");
exit(1);
}
if(wait(NULL) == -1 )//回收子进程状态,避免僵尸进程
{
perror("fail to wait");
exit(1);
}
}
return 0;
}