分类: LINUX
2007-05-13 12:48:29
练习三:内核定时器
一Linux下得时间
1.时间的测量
有时候要计算程序执行的时间.比如要对算法进行时间分析.这个时候可以使用下面这个函数.
#include
int gettimeofday(struct timeval *tv,struct
timezone *tz);
gettimeofday将时间保存在结构tv之中.tz一般使用NULL来代替.
2. 什么是linux 的itimer 机制
itimer 是internal
timer 的缩写,它是建立在linux 的timer 机制上的,可以在定时
器时间到并触发后,自我进行重新设置的间隔定时器。系统为每个进程提供了三个间隔定时器,分别在各自独立的一个时间区域内递减。当其中任意一个定时器到期时,就会发出一个信号给进程,同时,定时器重新开始运作。三种定时器描述如下:
ITIMER_REAL 真实时钟,到期时送出SIGALRM 信号。
ITIMER_VIRTUAL 仅在进程运行时的计时,到期时送出SIGVTALRM 信号。
ITIMER_PROF 不仅在进程运行时计时,在系统为进程运作而运行时它也计
时,与ITIMER_VIRTUAL
对比,该定时器通常为那些在用户态和核心态空间运行的应用所花去的时间计时,到期时送出SIGPROF
信号。
3、 Linux 的普通timer 机制和它的数据结构
1)Jiffies: 这是一个长整数,表示以10ms 为单位的系统时间。Jiffies
初始设置为0,只要系统一直运行,Jiffies
就不断增加。
2)Timeval 结构:用于保存时间值,分为两部分,其中tv_vec 保存的是整数秒部分,tv_usec
保存的是毫秒部分。
struct timeval {
int tv_sec; /* seconds */
int tv_usec; /* microseconds */
};
3)Itimerval
结构:用于保存某一个interval timer 的数据结构,其中两个成员是timeval
结构,一个是it_interval,用于保存timer 的时间间隔,也就是timer重新设置是的触发时间,另一个是it_value,保存的是当前在timer 中还剩下的时间值。
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};
4)进程控制块中的itimer 数据成员
在task_struct
结构中也有几个成员与三个itimer 有关:
struct task_struct { ┅ ┅
unsigned long it_real_value,
it_prof_value, it_virt_value;
unsigned long it_real_incr,
it_prof_incr, it_virt_incr;
┅ ┅
}
其中,it_****_value
用于设置itimer 第一次设置时的时间量,而it_****_incr
用于设置以后每次itimer 的重置。
关于这3个时间具体的操作函数是:
#include
int getitimer(int which,struct itimerval
*value);
int setitimer(int which,struct itimerval
*newval,struct itimerval *oldval);
getitimer函数得到间隔计时器的时间值.保存在value中 setitimer函数设置间隔计时器的时间值为newval.并将旧值保存在oldval中. which表示使用三个计时器中的哪一个. itimerval结构中的it_value是减少的时间,当这个值为0的时候就发出相应的信号了.
然后设置为it_interval值.
二Linux下的信号
1。信号的产生
信号事件的发生有两个来源: 一个是硬件的原因(比如我们按下了键盘),一个是软件的原因(比如我们使用系统函数或者是命令发出信号). 最常用的四个发出信号的系统函数是kill, raise, alarm和setitimer函数.
#include
#include
#i nclude
int
kill(pid_t pid,int sig);
int
raise(int sig);
unisigned int
alarm(unsigned int seconds);
kill系统调用负责向进程发送信号sig.
如果pid是正数,那么向信号sig被发送到进程pid.
如果pid等于0,那么信号sig被发送到所以和pid进程在同一个进程组的进程
如果pid等于-1,那么信号发给所有的进程表中的进程,除了最大的哪个进程号.
如果pid由于-1,和0一样,只是发送进程组是-pid.
2。信号的使用
信号是通过调用kill()函数产生并标识接受这个信号和信号类型的进程。实际上,正在接受的应用程序进程可以将一个信号按照默认的方式来处理,也可以将其忽略者使用用户定义的代码将其截获。系统调用signal()函数来标识编号和该信号的处理方法。
#include
void (*signal(int signo,void(*fun)(int)))(int)
说明:1 返回值是一个 void
(*)(int)类型的函数指针
2 signo是信号名
3 第二个参数为该信号的处理函数指针,类型为void (*)(int)
4 函数返回:成功则返回以前的信号处理配置函数指针,出错返回SIG_ERR
5 SIG_ERR原形为 #define SIG_ERR (void (*)())-1
程序中的信号处理例程;
static
void p_sig_handler(int signo)
{
switch(signo)
{
case SIGALRM: //SIGALRM信号到来
{
p_realt_secs++; //父进程real运行时间+1秒
signal(SIGALRM, p_sig_handler); //调用信号处理函数时间继续走
break;
}
case SIGVTALRM: //同上
{
p_virtt_secs++; //同上
signal(SIGVTALRM, p_sig_handler );
//同上
break;
}
case SIGPROF: //同上
{
p_proft_secs++; //同上
signal(SIGPROF, p_sig_handler ); //同上
break;
}
default: break; //不要出现
}
}