c语言版定时器
时间:2014年06月15日 人气:...

今晚研究了下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;


热门评论