自学Linux--Linux计时器

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值