今晚研究了下linux下的定时器,发现用户态并没有现成的封装好的接口,系统提供的这几个使用比较繁琐:
1.alarm:使用信号触发超时动作,一个进程只能拥有一个,感觉很土。
2.setitimer:原理同alarm,
功能比alarm强大,但也是采用信号触发超时动作,仍然感觉很土。
3.timerfd_create:这个会创建一个文件描述符,实现了linux一切皆设备的实现,主要和epoll等搭配使用,亲自试了一把,确实很好用,但是这个需要有
epoll_wait阻塞住持续调度,普通场合不一定方便使用。
4.timer_create:这个既可以靠信号触发,也可以起线程触发超时处理,比前前面几种较为简单,于是,对这个接口进行了简单的分装,以方便日常中使用。
注意:这套接口并没有严格测试,可不保证问题哦。。。。
//timer.h
#ifndef __TIMER_H__
#define __TIMER_H__
/* 秒级定时器,线程机制创建 */
/* 包含此定时器编译链接时需添加 -lrt 选项 */
/* flags值: 非循环定时器0,循环定时器1 */
#define NO_LOOP 0
#define LOOP_TIMER 1
/* 定时器超时处理函数 */
typedef void (*timer_callback_pf)(void *arg);
/* 创建定时器,成功返回定时器id,失败返回-1。*/
/* flags区分循环和非循环定时器;interval间隔时间,单位为秒。*/
/* callback为超时回调,不可为空; arg为超时回调处理参数,可为空。 */
long timer_add(unsigned int flags, int interval, timer_callback_pf callback, void *arg);
/* 定时器修改函数,修改之后会重新计时,成功返回0,失败返回-1 */
/* flags区分循环和非循环定时器;interval间隔时间,单位为秒。*/
int timer_mod(long timer_id, int flags, int interval);
/* 获取定时器剩余时间,成功返回剩余秒数,失败返回-1 */
long timer_get(long timer_id);
/* 删除定时器,成功返回0,失败返回-1 */
int timer_del(long timer_id);
#endif
//timer.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "timer.h"
/* 最大定时器个数 */
#define TIMER_MAX 10
struct timer_data{
timer_callback_pf callback; /* 定时器超时回调 */
void *arg; /* 定时器超时回调参数 */
};
struct timer_handle{
struct timer_data *p; /* 定时器超时数据 */
timer_t timerid; /* 定时器id*/
};
struct timer_count{
unsigned int count; /* 已经创建的定时器个数 */
struct timer_handle handle[TIMER_MAX]; /* 超时数据数组 */
};
/* 记录创建的定时器超时处理数据 */
static struct timer_count g_stdata;
/* 定时器超时外层回调处理函数 */
static void expire_func(union sigval data)
{
struct timer_data *p;
p = (struct timer_data *)data.sival_ptr;
/* 执行真实注册的超时回调 */
p->callback(p->arg);
}
/* 创建定时器,成功返回定时器id,失败返回-1。*/
/* flags区分循环和非循环定时器;interval间隔时间,单位为秒。*/
/* callback为超时回调,不可为空; arg为超时回调处理参数,可为空。 */
long timer_add(unsigned int flags, int interval, timer_callback_pf callback, void *arg)
{
int ret;
timer_t timerid;
unsigned int count;
struct sigevent stevp;
struct itimerspec stvalue;
struct timer_data *p = NULL;
/* 入参判断 */
if ((1 < flags) || (NULL == callback) || (TIMER_MAX <= g_stdata.count))
{
printf("Parameter error.");
return -1;
}
/* 分配内存 */
p = (struct timer_data *)malloc(sizeof(struct timer_data));
if (NULL == p)
{
printf("memory no enough.");
return -1;
}
/* 保存超时回调 */
memset(p, 0, sizeof(struct timer_data));
p->callback = callback;
p->arg = arg;
/* 设置属性,按线程创建定时器 */
memset(&stevp, 0, sizeof(stevp));
stevp.sigev_notify = SIGEV_THREAD;
stevp.sigev_value.sival_ptr = p;
stevp.sigev_notify_function = expire_func;
/* 创建定时器 */
ret = timer_create(CLOCK_REALTIME, &stevp, &timerid);
if (0 > ret)
{
perror("timer_create");
free(p);
return -1;
}
/* 保存全局超时处理数据,全局变量默认初始化必然为0 */
for (count = 0; count < TIMER_MAX; count++)
{
if (0 == g_stdata.handle[count].timerid)
{
g_stdata.handle[count].p = p;
g_stdata.handle[count].timerid = timerid;
g_stdata.count++;
break;
}
}
/* 填充超时时间 */
memset(&stvalue, 0, sizeof(stvalue));
stvalue.it_value.tv_sec = interval;
if (flags)
{
stvalue.it_interval.tv_sec = interval;
}
/* 设置超时时间 */
ret = timer_settime(timerid, 0, &stvalue, NULL);
if (0 > ret)
{
perror("timer_settime");
free(p);
if(timer_delete(timerid))
{
perror("timer_delete");
}
return -1;
}
return (long)timerid;
}
/* 定时器修改函数,修改之后会重新计时,成功返回0,失败返回-1 */
/* flags区分循环和非循环定时器;interval间隔时间,单位为秒。*/
int timer_mod(long timer_id, int flags, int interval)
{
int ret;
struct itimerspec stvalue;
/* 填充新的超时时间 */
memset(&stvalue, 0, sizeof(stvalue));
stvalue.it_value.tv_sec = interval;
if (flags)
{
stvalue.it_interval.tv_sec = interval;
}
/* 设置新的超时时间 */
ret = timer_settime((timer_t) timer_id, 0, &stvalue, NULL);
if (0 > ret)
{
perror("timer_settime");
}
return ret;
}
/* 获取定时器剩余时间,成功返回剩余秒数,失败返回-1 */
long timer_get(long timer_id)
{
int ret;
struct itimerspec stvalue;
memset(&stvalue, 0, sizeof(stvalue));
/* 获取剩余时间 */
ret = timer_gettime((timer_t) timer_id, &stvalue);
if(0 > ret)
{
perror("timer_gettime");
return -1;
}
return (long)stvalue.it_value.tv_sec;
}
/* 删除定时器,成功返回0,失败返回-1 */
int timer_del(long timer_id)
{
int ret;
unsigned int count;
struct itimerspec stvalue;
struct timer_data *p = NULL;
/* 清除超时时间设置 */
memset(&stvalue, 0, sizeof(stvalue));
ret = timer_settime((timer_t) timer_id, 0, &stvalue, NULL);
if (0 > ret)
{
perror("timer_settime");
}
/* 删除定时器 */
ret = timer_delete((timer_t) timer_id);
if(0 > ret)
{
perror("timer_delete");
}
/* 从全局变量查找超时数据,释放创建的内存 */
for (count = 0; count < TIMER_MAX; count++)
{
if ((timer_t)timer_id == g_stdata.handle[count].timerid)
{
p = g_stdata.handle[count].p;
free(p);
g_stdata.handle[count].p = NULL;
g_stdata.handle[count].timerid = 0;
g_stdata.count--;
break;
}
}
return ret;
}
//timer_test.c
#include <stdio.h>
#include "timer.h"
static void timer_exp1(void *arg)
{
printf("timer1 expire.");
long timer_id = *(long *)arg;
if (0 == timer_mod(timer_id, LOOP_TIMER, 5))
printf("timer2_id = %ld, modify done.", timer_id);
}
static void timer_exp2(void *arg)
{
printf("timer2 expire.");
}
static void timer_exp3(void *arg)
{
long timer_id = *(long *)arg;
printf("timer3_id = %ld, expire.", timer_id);
timer_del(timer_id);
printf("timer3 delete done.");
}
int main(int argc, char *argv[])
{
long timer1_id;
long timer2_id;
long timer3_id;
timer2_id = timer_add(LOOP_TIMER, 2, timer_exp2, NULL);
printf("timer2 id = %ld.", timer2_id);
timer1_id = timer_add(NO_LOOP, 10, timer_exp1, &timer2_id);
printf("timer1 id = %ld.", timer1_id);
timer3_id = timer_add(LOOP_TIMER, 5, timer_exp3, &timer3_id);
printf("timer3 id = %ld.", timer3_id);
while(1);
return 0;
}