概述
Linux应用层的定时器的实现起来很简单,这里介绍一种基于链表的定时器实现方法,在一个循环里面可以实现多个定时器。该方法无需依赖其他的库,你只需设置一个超时时间和相应的执行函数,系统就会在超时的时候执行一开始设置的函数。
注意点:超时的执行函数不能出现阻塞的任务,如涉及到句柄的读写,则需要设置该句柄为非阻塞模式。
代码结构介绍
创建一个timer的目录,在该目录下生成如下图所示的文件。
main.c调用定时器模块相关接口。
timelist.c timelist.h 定时器的具体实现,并提供相关的接口给其他模块调用。
Makefile 编译相关的代码,并生成可执行目标文件。
代码内容查看
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)
代码编译
代码编译只需要执行make clean;make即可,如下所示,最终生成一个timer_test可执行文件。
定时器运行验证
最后
以上就是沉静航空为你收集整理的Linux应用层的定时器简单实现的全部内容,希望文章能够帮你解决Linux应用层的定时器简单实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复