时间管理是计算机系统的主要任务。在时间管理中,经常利用定时器处理事情:比如tcp协议中利用定时器管理包超时,视频显示中利用定时器来定时显示视频帧,web服务中利用定时器来管理用户的超时,计划任务中按时激发任务。windows系统提供了SetTimer和timeSetEvent等定时器接口,Linux中则提供了setitimer等接口。这些函数的接口很类似,大体上都是用户提供回调函数和超时时间向OS注册一个定时器事件,OS在超时时间到了的时候,调用用户提供的回调函数来完成用户想要做的事情。windows下的接口支持单进程中拥有多个定时器,而linux则只允许单进程拥有一个定时器,因此在linux下的单进程中要使用多个定时器,则需要自己维护管理。另外,OS提供的定时器管理算法在大规模定时器的管理方面可能还不尽人意,这时候就需要用户去优化管理算法了,本文在这方面提供了一点素材。
这个实现允许用户使用多个自定义的定时器,每个自定义的定时器将周期地被触发直到其被删除。实现的主要思路是:
i)首先在初始化多定时器(mul_wheel_timer_init)时利用setitimer注册一个基本的时间单位(如1s)的定时事件;
ii)用户需要注册(mul_wheel_timer_set)自定义定时器时,在mul_wheel_timer_t结构中记录这个定时器的回调函数和定时周期等参数;
iii)当基本的时间单位到期后(如SIGALRM信号到达时),遍历整个mul_wheel_timer,如果有自定义定时器的超时时间到了,就执行相应的回调函数,并将自定义定时器的超时时间置为最初值;否则将自定义定时器的超时时间相应地减一个基本的时间单位;
下面是linux下的C代码(mul_wheel_timer.h):
/***********************************************************************
* Copyright (c) 2018 pepstack, pepstack.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
***********************************************************************/
/**
* mul_wheel_timer.h
* multi wheel timer for linux
*
* refer:
* http://blog.csdn.net/zhangxinrun/article/details/5914191
* https://linux.die.net/man/2/setitimer
*
* author: [email protected]
*
* create: 2018-02-03
* update: 2018-02-03
*/
#ifndef MUL_WHEEL_TIMER_H_INCLUDED
#define MUL_WHEEL_TIMER_H_INCLUDED
#if defined(__cplusplus)
extern "C"
{
#endif
#include <assert.h>
#include
#include
#include
#include
#include
#include
#define MAX_TIMER_CNT 10
#define MUL_TIMER_RESET_SEC 10
#define TIMER_UNIT 60
#define MAX_FUNC_ARG_LEN 100
#define INVALID_TIMER_HANDLE (-1)
typedef int timer_handle_t;
typedef struct mul_wheel_timer_t
{
struct _timer_info
{
int state; /* ON(1) or OFF(0) */
int interval;
int elapse; /* 0~interval */
int (* timer_func) (void *arg, int arglen);
char tmfn_arg[255];
int tmfn_arglen;
} timer_info[MAX_TIMER_CNT];
void (* old_sigfunc)(int);
void (* new_sigfunc)(int);
struct itimerval value, oldvalue;
} * mul_wheel_timer_t;
__attribute__((used))
static struct mul_wheel_timer_t mul_wheel_timer;
__attribute__((used))
static void sigfunc_ontimer(int signo)
{
int i;
for (i = 0; i < MAX_TIMER_CNT; i++) {
if (mul_wheel_timer.timer_info[i].state == 0) {
continue;
}
mul_wheel_timer.timer_info[i].elapse++;
if (mul_wheel_timer.timer_info[i].elapse == mul_wheel_timer.timer_info[i].interval) {
mul_wheel_timer.timer_info[i].elapse = 0;
mul_wheel_timer.timer_info[i].timer_func(mul_wheel_timer.timer_info[i].tmfn_arg, mul_wheel_timer.timer_info[i].tmfn_arglen);
}
}
}
/**
* success, return 0;
* failed, return -1
*/
__attribute__((used))
static int mul_wheel_timer_init (void)
{
int ret;
bzero(&mul_wheel_timer, sizeof(struct mul_wheel_timer_t));
if ( (mul_wheel_timer.old_sigfunc = signal(SIGALRM, sigfunc_ontimer)) == SIG_ERR ) {
return (-1);
}
mul_wheel_timer.new_sigfunc = sigfunc_ontimer;
mul_wheel_timer.value.it_value.tv_sec = MUL_TIMER_RESET_SEC;
mul_wheel_timer.value.it_value.tv_usec = 0;
mul_wheel_timer.value.it_interval.tv_sec = TIMER_UNIT;
mul_wheel_timer.value.it_interval.tv_usec = 0;
ret = setitimer(ITIMER_REAL, &mul_wheel_timer.value, &mul_wheel_timer.oldvalue);
return (ret);
}
/**
* success, return 0;
* failed, return -1
*/
__attribute__((used))
static int mul_wheel_timer_destroy (void)
{
int ret;
if ((signal(SIGALRM, mul_wheel_timer.old_sigfunc)) == SIG_ERR) {
return (-1);
}
ret = setitimer(ITIMER_REAL, &mul_wheel_timer.oldvalue, &mul_wheel_timer.value);
if (ret < 0) {
return (-1);
}
bzero(&mul_wheel_timer, sizeof(struct mul_wheel_timer_t));
return(0);
}
/**
* success, return 0;
* failed, return -1
*/
__attribute__((used))
static int mul_wheel_timer_del (timer_handle_t handle)
{
if (handle < 0 || handle >= MAX_TIMER_CNT) {
return (-1);
}
bzero(&mul_wheel_timer.timer_info[handle], sizeof(mul_wheel_timer.timer_info[handle]));
return (0);
}
/**
* success, return timer handle (0 based);
* failed, return -1
*/
__attribute__((used))
static timer_handle_t mul_wheel_timer_set (int interval, int (* timer_func) (void *arg, int arglen), void *arg, int arglen)
{
timer_handle_t i;
if (! timer_func || interval <= 0) {
return INVALID_TIMER_HANDLE;
}
for (i = 0; i < MAX_TIMER_CNT; i++) {
if (mul_wheel_timer.timer_info[i].state == 1) {
continue;
}
bzero(&mul_wheel_timer.timer_info[i], sizeof(mul_wheel_timer.timer_info[i]));
mul_wheel_timer.timer_info[i].timer_func = timer_func;
if (arg) {
if (arglen > MAX_FUNC_ARG_LEN) {
return INVALID_TIMER_HANDLE;
}
memcpy(mul_wheel_timer.timer_info[i].tmfn_arg, arg, arglen);
mul_wheel_timer.timer_info[i].tmfn_arglen = arglen;
}
mul_wheel_timer.timer_info[i].interval = interval;
mul_wheel_timer.timer_info[i].elapse = 0;
mul_wheel_timer.timer_info[i].state = 1; /* timer is ON */
break;
}
if (i >= MAX_TIMER_CNT) {
/* full */
return INVALID_TIMER_HANDLE;
}
/* success return timer index */
return (i);
}
#if defined(__cplusplus)
}
#endif
#endif /* MUL_WHEEL_TIMER_H_INCLUDED */
这样的定时器具有明显的缺陷:
程序中有些小bug,如对新建超时时间为0的定时器没有妥善的处理。
下面将对其进行改进 !
参考文章 [1]: http://blog.csdn.net/zhangxinrun/article/details/5914191