Linux中信号的种类:
SIGHUP 当终止一个终端时,内核就把这种信号发送给该终端所控制的所有进程.
SIGINT 当一个用户按下中断键(ctrl+c)后,内核就向该终端用关联的所有进程发送这个信号.
SIGQUIT 当用户按下(ctrl+),内核就向该终端用关联的所有进程发送这个信号.
SIGILL 当一个进程企图执行一条非法指令时,内核就发送这个信号.
SIGFPE 当产生浮点错误时,内核就发送这个信号.
SIGKILL 这是一个非常特殊的信号,他可以从一个进程发送到另一个进程,使接收到该信号的进程终止.内核偶然也发送这种信号.
SIGALRM 当一个定时器到时的时候,内核就发送这个信号.
SIGSTOP 子进程结束信号.UNIX用它来实现系统调用exit(),wait();
Linux中,可以用signal函数接受上面的各种信号,并可以指定接受到这些信号之后的“动作”
#include<signal.h>
typedef void (*sighandler_t)( int )
sighandler_t signal(int signum , sighandler_t handler)
当handler为:
SIG_IGN 忽略这个信号.
SIG_DFL 恢复对这个信号的默认处理.
/*
alarm & signal函数
功能:每隔一定的时间就去执行一次相应的操作(catch函数)
*/
#include<stdio.h>
#include<unistd.h>
#include<sys/time.h>
#include<signal.h>
void catch(int ) ;
int main(){
int i;
signal(SIGALRM,catch);
for(i=1;i<=6;++i){
alarm(3) ; /*设置一个3 sec的闹钟*/
sleep(3) ; /*每回合sleep 3 sec*/
}
return 0;
}
void catch(int sig){
printf("Time up!\n");
}
执行结果:
除此之外,Linux还提供了3个内置的计时器:
ITIMER_REAL:实时定时器,不管进程在何种模式下运行(甚至在进程被挂起时),它总在计数。定时到达,向进程发送SIGALRM信号。
ITIMER_VIRTUAL:这个不是实时定时器,当进程在用户模式(即程序执行时)计算进程执行的时间。定时到达后向该进程发送SIGVTALRM信号。
ITIMER_PROF:进程在用户模式(即程序执行时)和核心模式(即进程调度用时)均计数。定时到达产生SIGPROF信号。ITIMER_PROF记录的时间比ITIMER_VIRTUAL多了进程调度所花的时间。
定时器在初始化是,被赋予一个初始值,随时间递减,递减至0后发出信号,同时恢复初始值。在任务中,我们可以一种或者全部三种定时器,但同一时刻同一类型的定时器只能使用一个。用到的函数有:
#include<sys/time.h>
int getitimer(int which , struct itimerval *curr_value) ;
int setitimer(int which , struct itimerval *new_value , struct itimerval *old_value);
which是模式,有ITIMER_REAL, ITIMER_VIRTUAL. ITIMER_PROF三种模式。
struct itimerval{
struct timeval it_interval ; /*时间间隔*/
struct timeval it_value ; /*当前时间计数*/
}
struct timeval{
long tv_sec ; /*秒*/
long tv_usec ; /*毫秒*/
}
it_interval用来指定每隔多长时间执行任务, it_value用来保存当前时间离执行任务还有多长时间。比如说, 你指定it_interval为2秒(微秒为0),开始的时候我们把it_value的时间也设定为2秒(微秒为0),当过了一秒, it_value就减少一个为1, 再过1秒,则it_value又减少1,变为0,这个时候发出信号(告诉用户时间到了,可以执行任务了),并且系统自动把it_value的时间重置为it_interval的值,即2秒,再重新计数。
/* Sample .1 : Linux内置的计时器计时. */ #include<stdio.h> #include<sys/time.h> #include<unistd.h> #include<signal.h> /*信号处理函数*/ static void Sighandler(int signo) ; /*信号处理中的辅助函数*/ void TimePassed(struct itimerval *itimer , struct timeval *tv) ; void Kernel_Time(struct timeval *itimer1, struct timeval *itimer2 , struct timeval *tv ) ; int main(int argc, char **argv){ /*变量定义*/ struct itimerval mytimer ; long i , cnt ; /*注册信号处理函数*/ signal(SIGUSR1 , Sighandler) ; signal(SIGALRM , Sighandler) ; fprintf(stdout, "Enter the Time between Loop! \n"); fscanf(stdin, "%ld" ,&cnt); cnt *= (1e6) ; /*初始化定时器 ,it_value为当前时间计数,it_interval为设定的时间间隔*/ mytimer.it_value.tv_sec = 10 ; mytimer.it_value.tv_usec = 0 ; mytimer.it_interval = mytimer.it_value ; /*注册定时器*/ setitimer(ITIMER_REAL,&mytimer , NULL); setitimer(ITIMER_VIRTUAL ,&mytimer, NULL); setitimer(ITIMER_PROF,&mytimer, NULL); while(1){ for(i = 0;i < cnt; ++i) ; /*完成一定的循环次数之后将一个用户信号SIGUSER1发送给自己*/ raise(SIGUSR1) ; } return 0; } /*信号处理函数*/ void Sighandler(int sig){ struct itimerval tmp_itimer ; struct timeval realtv, cputv, usertv , kerneltv ; /*获得当前实时定时器的时间*/ getitimer(ITIMER_REAL , &tmp_itimer); TimePassed(&tmp_itimer, &realtv ) ; /*获得当前CPU定时器的时间*/ getitimer(ITIMER_PROF , &tmp_itimer); TimePassed(&tmp_itimer, &cputv ) ; /*获得当前用户定时器的时间*/ getitimer(ITIMER_VIRTUAL ,&tmp_itimer); TimePassed(&tmp_itimer, &usertv); /*计算进程调度的时间 = CPU定时器时间 - 用户时间*/ Kernel_Time(&cputv , &usertv , &kerneltv) ; switch( sig ){ case SIGUSR1: printf("Rreal Time : %ld %ld\t",realtv.tv_sec, realtv.tv_usec); printf("CPU Time : %ld %ld\t",cputv.tv_sec,cputv.tv_usec); printf("User Time : %ld %ld\t",usertv.tv_sec , usertv.tv_usec); printf("Kernel Time : %ld %ld\n",kerneltv.tv_sec , kerneltv.tv_usec); break ; case SIGALRM: printf("Time up ,The process will eixt!\n"); //printf("Rreal Time : %ld %ld\t",realtv.tv_sec, realtv.tv_usec); printf("CPU Time : %ld %ld\t",cputv.tv_sec,cputv.tv_usec); printf("User Time : %ld %ld\t",usertv.tv_sec , usertv.tv_usec); printf("Kernel Time : %ld %ld\n",kerneltv.tv_sec , kerneltv.tv_usec); _exit(0) ; break ; //case SIGVTALRM: } } /*求两个时间的时间差*/ void TimePassed(struct itimerval *itimer, struct timeval *tv){ struct timeval temp1 , temp2 ; temp2 = itimer->it_value ; temp1 = itimer->it_interval ; if(temp1.tv_usec <= temp2.tv_usec){ temp1.tv_sec -- ; temp1.tv_usec += 1e6 ; } tv->tv_sec = temp1.tv_sec - temp2.tv_sec ; tv->tv_usec = temp1.tv_usec - temp2.tv_usec ; } /*计算内核的时间,即进程调度的时间*/ void Kernel_Time(struct timeval *it1, struct timeval *it2 , struct timeval *tv){ if(it1->tv_usec < it2->tv_usec ){ it1->tv_sec -- ; it1->tv_usec += 1e6 ; } tv->tv_sec = it1->tv_sec - it2->tv_sec ; tv->tv_usec = it1->tv_usec - it2->tv_usec ; }
运行结果:
/* Sample .2 Linux 系统内置计时器 */ #include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/time.h> void cal(int sig){ switch(sig){ case SIGALRM : /*捕获SIGALRM信号*/ printf("Catch a signal -- SIGALRM!\n"); break ; case SIGVTALRM :/*捕获SIGVTALRM 信号*/ printf("Catch a signal -- SIGVTALRM!\n"); break ; case SIGINT : /*捕获SIGINT信号,要是终端输入CTRL+C内核就向与终端相关的进程发送这个信号*/ _exit(0) ; break ; } return ; } int main(int argc, char **argv){ struct itimerval value,ovalue,value2 ; printf("Process: %d\n",getpid()); signal(SIGALRM,cal) ; signal(SIGVTALRM,cal) ; signal(SIGINT,cal); value.it_value.tv_sec = 2 ; value.it_value.tv_usec = 0 ; value.it_interval = value.it_value ; setitimer(ITIMER_REAL, &value ,&ovalue); value2.it_value.tv_sec = 1 ; value2.it_value.tv_usec = 0 ; value2.it_interval = value2.it_value ; setitimer(ITIMER_VIRTUAL, &value2 ,&ovalue); while(1) ; return 0; }