linux下精密定时器

转自:http://blog.163.com/hong_nt/blog/static/10468917120081130103632925/


软件定时器的主要功能是实现状态机的超时机制和实现基于超时的计数功能。
由于协议状态机运行于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; i<MAX_TIMERS; i++){
                if(T.inuse && !T.set){
                        if(T.expire<delta){
                                T.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; i<MAX_TIMERS; i++){
                        if(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;i<MAX_TIMERS;i++){
                T.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; i<MAX_TIMERS; i++){
                        
                        if(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(i<N_TIMERS){
                        T.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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中,有几种方法可以实现定时器功能: 1. 使用系统调用 alarm():该调用会在指定的时间(以秒为单位)后触发SIGALRM信号。可以通过注册信号处理函数来处理该信号,实现定时器功能。例如: ``` #include <unistd.h> #include <signal.h> void handler(int signum) { // 定时器触发后的处理逻辑 } int main() { signal(SIGALRM, handler); alarm(5); // 5秒后触发SIGALRM信号 while (1) {} // 持续运行程序,直到收到SIGALRM信号 return 0; } ``` 2. 使用timer_create()函数:该函数可以创建一个定时器,精度可以达到毫秒级别。例如: ``` #include <time.h> #include <signal.h> void handler(int signum) { // 定时器触发后的处理逻辑 } int main() { struct sigevent sev; timer_t timerid; struct itimerspec its; // 创建定时器 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGUSR1; sev.sigev_value.sival_ptr = &timerid; timer_create(CLOCK_REALTIME, &sev, &timerid); // 设置定时器 its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; its.it_interval.tv_nsec = 0; timer_settime(timerid, 0, &its, NULL); // 注册信号处理函数 signal(SIGUSR1, handler); while (1) {} // 持续运行程序,直到收到SIGUSR1信号 return 0; } ``` 3. 使用select()函数:该函数可以等待多个文件描述符中的任意一个就绪,可以通过设置超时时间实现定时器功能。例如: ``` #include <stdio.h> #include <sys/select.h> int main() { fd_set rfds; struct timeval tv; while (1) { // 清空文件描述符集合 FD_ZERO(&rfds); // 设置需要监视的文件描述符 FD_SET(0, &rfds); // 监视标准输入 // 设置超时时间 tv.tv_sec = 5; tv.tv_usec = 0; // 等待文件描述符就绪或超时 int ret = select(1, &rfds, NULL, NULL, &tv); if (ret == -1) { perror("select"); } else if (ret == 0) { printf("Timeout\n"); // 超时处理逻辑 } else { if (FD_ISSET(0, &rfds)) { printf("Input available\n"); // 文件描述符就绪处理逻辑 } } } return 0; } ``` 这些方法都可以实现定时器功能,选择哪种方法取决于具体的场景和需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值