我是靠谱客的博主 沉静航空,最近开发中收集的这篇文章主要介绍Linux应用层的定时器简单实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Linux应用层的定时器的实现起来很简单,这里介绍一种基于链表的定时器实现方法,在一个循环里面可以实现多个定时器。该方法无需依赖其他的库,你只需设置一个超时时间和相应的执行函数,系统就会在超时的时候执行一开始设置的函数。

注意点:超时的执行函数不能出现阻塞的任务,如涉及到句柄的读写,则需要设置该句柄为非阻塞模式。

  1. 代码结构介绍

创建一个timer的目录,在该目录下生成如下图所示的文件。

main.c调用定时器模块相关接口。

timelist.c timelist.h 定时器的具体实现,并提供相关的接口给其他模块调用。

Makefile 编译相关的代码,并生成可执行目标文件。

  1. 代码内容查看

timelist.h内容如下所示:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/queue.h>
#include <termios.h> 
#include <time.h>
/*
一个定时器对应一个节点
*/
typedef struct timer_node_s {
    unsigned char run_once;
    unsigned long long intv_ms;
    unsigned long long last_tick;
    void *ptr;
    void (*do_exe_env)(void *ptr);
    CIRCLEQ_ENTRY(timer_node_s) link;
}timer_node_t;

/*
定义链表
*/
typedef struct circleq_head {                                
    struct timer_node_s *cqh_first;        /* first element */    
    struct timer_node_s *cqh_last;        /* last element */
}timer_list_head_t;

void timer_list_init(timer_list_head_t *circleq_head);//初始化定时器链表
void timer_env_add(timer_list_head_t *circleq_head,  int intv_ms, void *func, void *ptr);//添加一个无限循环的定时器
void timer_env_add_once(timer_list_head_t *circleq_head,  int intv_ms, void *func, void *ptr);//添加一个只执行一次的定时器
void timer_list_check_env(timer_list_head_t *circleq_head);//定时器超时检测及相关事件执行
timelist.c内容如下所示:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/queue.h>
#include <termios.h> 
#include <time.h>

#include "timerlist.h"
/*
获取当前系统的时间,精确到毫秒
*/
unsigned long long timer_get_now_tick(void)  
{  
    struct timespec ts;  
    unsigned long long value = 0;;
    clock_gettime(CLOCK_MONOTONIC, &ts);  
    value = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
    return value;  
} 
/*
定时器链表初始化
*/
void timer_list_init(timer_list_head_t *circleq_head)
{
    CIRCLEQ_INIT(circleq_head);
}
/*
添加一个节点
*/
void timer_list_node_add(timer_list_head_t *circleq_head, timer_node_t *elm)
{
    CIRCLEQ_INSERT_TAIL(circleq_head, elm, link);
}
/*
删除定时器
*/
void timer_list_node_del(timer_list_head_t *circleq_head, void *func)
{
    timer_node_t *n;
    for (n = circleq_head->cqh_first; n != (void *)circleq_head;
        n = n->link.cqe_next) {
        if (n->do_exe_env== func) {
            CIRCLEQ_REMOVE(circleq_head, n, link);
            free(n);
            break;
        }
    }
}
/*
添加定时器
*/
void timer_list_add(int run_once, timer_list_head_t *circleq_head,  int intv_ms, void *func, void *ptr)
{
    timer_node_t *n = (timer_node_t *)malloc(sizeof(timer_node_t));
    memset(n, 0, sizeof(timer_node_t));
    n->intv_ms = intv_ms;
    n->do_exe_env = func;
    n->ptr = ptr;
    n->run_once = run_once;
    n->last_tick = timer_get_now_tick();
    timer_list_node_add(circleq_head, n);
}
/*
添加一个无限循环的定时器
*/
void timer_env_add(timer_list_head_t *circleq_head,  int intv_ms, void *func, void *ptr)
{
    timer_list_add(0, circleq_head,intv_ms, func, ptr);
}
/*
添加一个只执行一次的定时器
*/
void timer_env_add_once(timer_list_head_t *circleq_head,  int intv_ms, void *func, void *ptr)
{
    timer_list_add(1, circleq_head,intv_ms, func, ptr);
}
/*
定时器超时检测及相关事件执行,该函数需要放到一个循环里面反复执行
*/
void timer_list_check_env(timer_list_head_t *circleq_head)
{
    timer_node_t *n;
    for (n = circleq_head->cqh_first; n != (void *)circleq_head;
        n = n->link.cqe_next) {
        unsigned long long nowtick = timer_get_now_tick();
        if(abs(nowtick-n->last_tick)>=n->intv_ms) {
            n->last_tick = nowtick;
            if(n->do_exe_env) {
                n->do_exe_env(n->ptr);
                if(n->run_once) {
                    timer_list_node_del(circleq_head, n->do_exe_env);
                }
            }
        }
    }
}
main.c内容如下所示:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/queue.h>
#include <termios.h> 
#include <time.h>
#include <stdarg.h>

#include "timerlist.h"

int get_timestamp(char * timedate)
{
    time_t timep;
    struct timeval tv_tm, tv_now;

    struct tm *p, pp;
    time(&timep);

    localtime_r(&timep, &pp);
    p = &pp;

    sprintf(timedate, "%04d-%02d-%02d %02d:%02d:%02d",p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
}

void LOG(const char *format,...)
{
    char timebuf[48]="";
    get_timestamp(timebuf);
    va_list argptr;
    char buffer[2048];
    va_start(argptr,format);
    vsprintf(buffer,format,argptr);
    va_end(argptr);
    printf("[%s]%s", timebuf, buffer);
}
/*
执行函数
*/
void timer_hander_1(void *arg)
{
    if(arg) {
        int env_id = *(int *)arg;
        LOG("[%s](%d)env_id:%dn", __func__,__LINE__, env_id);
    }
}
/*
执行函数
*/

void timer_hander_2(void *arg)
{
    if(arg) {
        int env_id = *(int *)arg;
        LOG("[%s](%d)env_id:%dn", __func__,__LINE__, env_id);
    }
}

void main()
{
    timer_list_head_t timer_que;

    timer_list_init(&timer_que);
    int env_id_1 = 100;
    int env_id_2 = 200;
/*
添加无线循环的定时器
*/
    timer_env_add(&timer_que, 1000, timer_hander_1, (void *)&env_id_1);
/*
添加只执行一次的定时器,定时时间为5秒
*/
    timer_env_add_once(&timer_que, 5000, timer_hander_2, (void *)&env_id_2);
    
    while(1) {
        timer_list_check_env(&timer_que);
        usleep(1000);
    }
    
}
Makefile内容如下:
CPROG    = timer_test
BIN     = $(CPROG) 
CC= gcc
OBJS=main.o timerlist.o
all: $(BIN) 
clean:
    rm -f $(OBJS) $(BIN)
$(BIN): $(OBJS)
    $(CC)  -o $(BIN) $(OBJS)   $(CFLAGS) $(LDFLAGS) $(CFLAGS_EXTRA)
  1. 代码编译

代码编译只需要执行make clean;make即可,如下所示,最终生成一个timer_test可执行文件。

  1. 定时器运行验证

最后

以上就是沉静航空为你收集整理的Linux应用层的定时器简单实现的全部内容,希望文章能够帮你解决Linux应用层的定时器简单实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部