Linux多定时器的实现之一

Linux多定时器的实现之一

时间管理是计算机系统的主要任务。在时间管理中,经常利用定时器处理事情:比如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 <stdio.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>

#include <time.h>
#include <sys/time.h>


#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 */

这样的定时器具有明显的缺陷:

  • 新建定时器、遍历定时器和删除定时器(查找哪个定时器超时)时时间复杂度都为O(n)(n是定时器的个数);
  • 适用环境是单线程环境,如要用于多线程,需添加同步操作。
  • 程序中有些小bug,如对新建超时时间为0的定时器没有妥善的处理。

    下面将对其进行改进 !

参考文章 [1]: http://blog.csdn.net/zhangxinrun/article/details/5914191

猜你喜欢

转载自blog.csdn.net/cheungmine/article/details/79246203
今日推荐