概述
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 %ldt",realtv.tv_sec, realtv.tv_usec);
printf("CPU Time : %ld %ldt",cputv.tv_sec,cputv.tv_usec);
printf("User Time : %ld %ldt",usertv.tv_sec , usertv.tv_usec);
printf("Kernel Time : %ld %ldn",kerneltv.tv_sec , kerneltv.tv_usec);
break ;
case SIGALRM:
printf("Time up ,The process will eixt!n");
//printf("Rreal Time : %ld %ldt",realtv.tv_sec, realtv.tv_usec);
printf("CPU Time : %ld %ldt",cputv.tv_sec,cputv.tv_usec);
printf("User Time : %ld %ldt",usertv.tv_sec , usertv.tv_usec);
printf("Kernel Time : %ld %ldn",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: %dn",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;
}
最后
以上就是强健牛排为你收集整理的自学Linux--Linux计时器的全部内容,希望文章能够帮你解决自学Linux--Linux计时器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复