linux用户态定时器,linux下精密定时器

在linux下的精密定时器

软件定时器的主要功能是实现状态机的超时机制和实现基于超时的计数功能。

由于协议状态机运行于Linux内核之上,也就是说在用户态运行。在Linux系统中,用户态应用程序只能调用三个定时器:ITIMER_REAL、 ITIMER_VIRTUAL和ITIMER_PROF。而在协议状态机中需要32个定时器,所以需要新的机制来完成定时功能。

软件定时器主要被用来解决硬件定时器的物理限制,并为应用程序提供更加灵活的定时器编程接口。定时器最基本的作用就是允许某个任务在将来某个特定时间点运 行。定时器超时,被注册的任务开始运行,在我们的系统中,和定时器相关的任务就是产生某个定时器超时事件。我们定义最基本的定时器结构Timer,当作我 们的软件定时器对象:

#define MAX_TIMERS N   //N为你需要的定时器的个数

struct Timer{

long timeout;                      // 定时器超时时间,单位毫秒ms

long expire;                      // 下一次中断时定时器剩余的超时时间,单位毫秒ms

int inuse;                      // 定时器是否被使用

int set;                                // 定时器是否超时

int signal;                      // 定时器超时时,发送的事件类型

int param;                      // 定时器超时时,发送的事件类型的参数

}T[MAX_TIMERS];// 定时器集合

软件定时器提供给应用程序的接口主要有4个:

Int init_timers();                                // 初始化定时器集合

Int start_timer(struct Timer *T);        // 启动定时器T

Int stop_timer(struct Timer *T);        // 停止定时器T

Int get_event();                                // 查询超时的定时器事件

程序初始化时调用init_timers()初始化定时器集合,初始化之后就可以在系统中调用start_timer()和stop_timer()来使用定时器功能。协议状态机循环调用get_event()查询超时的定时器事件,输入到协议状态机内部。

软件定时器基于一个内部的由Linux操作系统提供的定时器ITIMER_REAL,实际的定时工作都由该定时器完成。定时器ITIMER_REAL每次 超时时,调用update_timers()更新定时器集合,将超时的定时器的set位置位,并查询定时器集合中所有已经启动的定时器,选择expire 值最小的那个定时器,用该expire值来重置定时器ITIMER_REAL,并更新定时器集合中所有已启动定时器的expire值。也就是说在该 expire毫秒后,定时器ITIMER_REAL将重新发生超时中断,重复以上过程。如果没有软件定时器被启动,定时器ITIMER_REAL将被清 零,直到下一次调用start_timer()。

如果在两次中断之间调用start_timer(struct Timer *T),将会比较T->expire值和离下一次时钟中断的时间间隔time_remain。如果T->expire小于 time_remain,则将把T作为最小定时器,用T->expire重置内部定时器ITIMER_REAL,并更新定时器集合中所有已启动定时 器的expire值;如果T->expire不小于time_remain,则只需更新T的expire值。

stop_timer(struct Timer *T)只需将T的使用标识位insue置零,在更新定时器集合时就会被自动忽略。

部分代码如下:

程序soft_timer.c:

#include "soft_timer.h"

int delta = 10;

long start = 0;

struct itimerval phy_timer;

struct itimerval old_timer;

struct Timer *cur_timer;

void update_timers(int sig)

{

int i = 0;

int min_timer = -1;

long min_expire = 1000000000;

if(cur_timer->inuse)cur_timer->set = 1;

for(i=0; iif(T.inuse && !T.set){

if(T.expireT.set = 1;

}else if(T.expire > 0 && min_expire>T.expire){

min_expire = T.expire;

min_timer = i;

}

}

}

if(min_timer<0){

timerclear(&(phy_timer.it_value));

timerclear(&(phy_timer.it_interval));

}else{

phy_timer.it_value.tv_sec = min_expire/1000;

phy_timer.it_value.tv_usec = (min_expire%1000)*1000;

timerclear(&(phy_timer.it_interval));

cur_timer = &T[min_timer];

for(i=0; iif(T.inuse && !T.set){

T.expire -= min_expire;

}

}

}

setitimer(ITIMER_REAL, &phy_timer, NULL);

}

int create_phy_timer(struct itimerval *timer, void (*handler)(int))

{

int rc = 0;

struct sigaction sa;

memset (&sa, 0, sizeof (sa));

sa.sa_handler = handler;

sigaction(SIGALRM, &sa, NULL);

timerclear(&(timer->it_value));

timerclear(&(timer->it_interval));

setitimer(ITIMER_REAL, timer, NULL);

return rc;

}

int init_timers()

{

int ret = 0;

int i = 0;

for(i=0;iT.inuse = 0;

T.param = 0;

T.set = 0;

T.timeout = 0;

T.expire = 0;

}

cur_timer = &T[0];

create_phy_timer(&phy_timer, update_timers);

}

int start_timer(struct Timer *t)

{

int ret = 0;

int i = 0;

long diff = 0;

long time_remain;

t->expire = t->timeout;

t->inuse = 1;

t->set = 0;

getitimer(ITIMER_REAL, &old_timer);

time_remain = old_timer.it_value.tv_sec*1000+old_timer.it_value.tv_usec/1000;

//printf("time_remain=%ld\n",time_remain);

if(time_remain==0){

phy_timer.it_value.tv_sec = t->timeout/1000;

phy_timer.it_value.tv_usec = (t->timeout%1000)*1000;

timerclear(&(phy_timer.it_interval));

setitimer(ITIMER_REAL, &phy_timer, NULL);

cur_timer = t;

return ret;

}

if(t->timeout+delta<=time_remain){

diff = time_remain - t->timeout;

for(i=0; iif(cur_timer==&T){

cur_timer->expire = diff;

}else if(t==&T){

}else if(T.inuse && !T.set){

T.expire +=   diff;

}

}

phy_timer.it_value.tv_sec = t->timeout/1000;

phy_timer.it_value.tv_usec = (t->timeout%1000)*1000;

timerclear(&(phy_timer.it_interval));

setitimer(ITIMER_REAL, &phy_timer, NULL);

cur_timer = t;

}else{

t->expire = t->timeout - time_remain;

//printf("t->expire =%ld\n", t->expire);

}

return ret;

}

int stop_timer(struct Timer *t)

{

int ret = 0;

t->inuse = 0;

t->expire = t->timeout;

t->set = 0;

return ret;

}

long current_millis()

{

struct timeval tv;

long   now;

gettimeofday(&tv, NULL);

now = (tv.tv_sec%100000)*1000+tv.tv_usec/1000;

return now;

}

void sleep_millis(long ms)

{

struct timespec tv;

tv.tv_sec = ms/1000;

tv.tv_nsec = (long)(ms%1000)*1000000;

nanosleep(&tv, NULL);

}

soft_timer.h头文件如下:

#define MAX_TIMERS N

struct Timer{

long timeout;

long expire;

int inuse;

int set;

int signal;

int param;

}T[MAX_TIMERS];

extern int init_timers();

extern int start_timer(struct Timer *t);

extern int stop_timer(struct Timer *t);

extern int start_phy_timer(struct Timer *t, void (*handler)(int));

extern int stop_phy_timer(struct Timer *t);

extern long current_millis();

extern void sleep_millis(long ms);

#ifdef __cplusplus

}

#endif

#endif /*__soft_timer_h*/

在调用的时候可以先将其初始化

init_timers();

for(i = 1; i< MAX_TIMERS; i++){

if(iT.timeout = timeouts;

T.signal = time_events;

}else{

T.timeout = T[13].timeout;

T.signal = T[13].signal;

}

}

随后在适当的时刻start_timer(&T[n]);或者stop_timer(&T[n]);就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个Linux用户定时器的简单例程: ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <time.h> #include <unistd.h> #define TIMER_SIG SIGRTMIN void timer_handler(int sig, siginfo_t *si, void *uc) { printf("Timer expired.\n"); } int main(int argc, char *argv[]) { timer_t timerid; struct sigevent sev; struct itimerspec its; struct sigaction sa; // 设置定时器信号处理函数 sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = timer_handler; sigemptyset(&sa.sa_mask); if (sigaction(TIMER_SIG, &sa, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } // 创建定时器 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = TIMER_SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) { perror("timer_create"); exit(EXIT_FAILURE); } // 设置定时器 its.it_value.tv_sec = 5; // 初始定时器时间为5秒 its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; // 定时器到期后每1秒重新启动一次 its.it_interval.tv_nsec = 0; if (timer_settime(timerid, 0, &its, NULL) == -1) { perror("timer_settime"); exit(EXIT_FAILURE); } // 循环等待定时器信号 while (1) { sleep(1); } return 0; } ``` 该程序使用 `timer_create()` 创建一个定时器,并使用 `timer_settime()` 设置定时器的初始值和周期值。在定时器到期时,会触发一个 `SIGRTMIN` 信号,该信号将被注册的信号处理函数 `timer_handler()` 捕获并执行。在该例程中,我们简单地打印了一条消息来表示定时器已经到期。 要编译上述程序,请使用以下命令: ``` gcc -o timer timer.c ``` 运行程序,它将等待5秒钟,然后输出一条消息,之后每隔1秒钟再输出一条消息。你可以使用 `Ctrl+C` 组合键来中断程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值