应用层timer_如何序列化timer

应用层使用timer可以启动多个timer(每个timer管理一个目标时间),也可启用一个timer来管理多个目标时间。

多个timer时每个timer占用一部分空间,且存在多个timer同时到期的先后顺序问题(未多考虑,是否有问题待确定),可采用单个timer管理程序所有定时事件,即如何实现序列化的timer。

涉及到链表(记录多个目标时间的到期时间),信号处理函数(在SIG_ALAM函数中处理timer事件,并启动下一个timer时间点)。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>

#include "list.h"

#define TIMERID_FIRST 100

typedef void (*stimer_func)(void *arg);

struct signal_timer{
    struct list_head list_timer;
    int id; 
    struct timeval itv;
    struct timeval atv;
    stimer_func stimer_handler; 
    void *arg;
};

int g_id;
struct list_head g_signal_list;

void alarm_handler(int sig);
int timer_init(void);
void timer_destroy(void);
// Return: id >0, in case of success; -1 in case of error.
int timer_add(long sec, long usec, void (*stimer_func)(void *arg), void *arg);
void timer_del(int id, int is_free);

static long long diff_time(struct timeval *t1, struct timeval *t2)
{
    long long t1_usec = (t1->tv_sec * 1000 * 1000  + t1->tv_usec);
    long long t2_usec = (t2->tv_sec * 1000 * 1000  + t2->tv_usec);

    return (t1_usec - t2_usec);
}
static int max_time(struct timeval *t1, struct timeval *t2)
{
    if(t1->tv_sec < t2->tv_sec){
        return -1; 
    } else if(t1->tv_sec > t2->tv_sec){
        return 1;
    } else {
        if(t1->tv_usec < t2->tv_usec){
            return -1;
        } else if(t1->tv_usec > t2->tv_usec){
            return 1;
        } else {
            return 0;
        }
    }
}

#define min_time(t1, t2) (((t1).tv_sec < (t2).tv_sec) || \
                (((t1).tv_sec == (t2).tv_sec) && \
                    ((t1).tv_usec < (t2).tv_usec)))

#define MAX_USEC    999999
#define TV_MINUS(t1, t2, target)  if((t1).tv_usec >= (t2).tv_usec){ \
        (target).tv_sec = (t1).tv_sec - (t2).tv_sec;\
        (target).tv_usec = (t1).tv_usec - (t2).tv_usec;\
    } else { \
        (target).tv_sec = (t1).tv_sec - (t2).tv_sec - 1;\
        (target).tv_usec = (t1).tv_usec + (MAX_USEC - (t2).tv_usec);\
    }
void alarm_handler(int sig)
{
    struct timespec ts;
    struct timeval tv;
    struct timeval tv_min, *ptv_min;
    struct itimerval it;
    struct signal_timer *pstimer = NULL, *next= NULL;
    int ret = 0;

    if(list_empty(&g_signal_list))
        return ;

//  pstimer = list_first_entry(&g_signal_list, struct signal_timer, list_timer);
//  ptv_min = &(pstimer->atv);
    ptv_min = &tv_min;

    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    tv.tv_sec = ts.tv_sec;
    tv.tv_usec = ts.tv_nsec / 1000;
//  printf("now time: %ld:%ld\n", tv.tv_sec, tv.tv_usec);

    tv_min = tv;
    tv_min.tv_sec += 1000; //default 1000s once 

    // two methods: sequence the timer list in case of more timers,  
    //              not sequence in case of fewer timers.   
    list_for_each_entry_safe(pstimer, next, &g_signal_list, list_timer){
//      printf("timerid:%d, aim time: %ld:%ld\n", pstimer->id, pstimer->atv.tv_sec, pstimer->atv.tv_usec);
        if(max_time(&pstimer->atv, &tv) <= 0){
            if(pstimer->stimer_handler != NULL){
                pstimer->stimer_handler(pstimer->arg);
            }
            // only operation once, when overflow more times.
            do{
                pstimer->atv.tv_sec += pstimer->itv.tv_sec;
                pstimer->atv.tv_usec += pstimer->itv.tv_usec;
            } while(max_time(&pstimer->atv, &tv) < 0);
//      } else {
//          break;
        }
        // get next itimer
        if(min_time(pstimer->atv, *ptv_min)){
            ptv_min = &(pstimer->atv);
        }
    }

    memset(&it, 0, sizeof(it));
//  it.it_value.tv_sec = ptv_min->tv_sec - tv.tv_sec;
//  it.it_value.tv_usec = ptv_min->tv_usec - tv.tv_usec;
    TV_MINUS(*ptv_min, tv, it.it_value);
    ret = setitimer(ITIMER_REAL, &it, NULL);
    if(ret < 0){
        perror("setitimer");
    }
    printf("process SIGALRM, next time is %ld:%ld\n", it.it_value.tv_sec, it.it_value.tv_usec);
}

int timer_add(long sec, long usec, void (*stimer_func)(void *arg), void *arg)
{
    struct signal_timer *pstimer = (struct signal_timer*)malloc(sizeof(struct signal_timer));
    struct timespec ts;

    memset(pstimer, 0, sizeof(*pstimer));
    pstimer->id = g_id++;
    pstimer->itv.tv_sec = sec;
    pstimer->itv.tv_usec = usec;
    pstimer->stimer_handler = stimer_func;
    if(arg){
        pstimer->arg = arg;
    }else {
        pstimer->arg = pstimer;
    }

    list_add(&(pstimer->list_timer), &g_signal_list);

    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    pstimer->atv.tv_sec += ts.tv_sec;
    pstimer->atv.tv_usec += ts.tv_nsec / 1000;

    return pstimer->id;
}
void timer_del(int id, int is_free)
{
    struct signal_timer *pstimer = NULL;

    list_for_each_entry(pstimer, &g_signal_list, list_timer){
        if(pstimer->id == id){
            list_del(&(pstimer->list_timer));

            printf("----delete timerid is %d\n", pstimer->id);
            if(is_free){
                free(pstimer);
            }
            break;
        }
    }
}

int timer_init(void)
{
    INIT_LIST_HEAD(&g_signal_list);
    struct sigaction act;
    int ret = 0;

//  memset(&act, 0, sizeof(act));
    sigemptyset(&act.sa_mask);
    act.sa_handler = alarm_handler;
    act.sa_flags = 0;

    ret = sigaction(SIGALRM, &act, NULL);
    if(ret < 0){
        perror("sigaction");
        return -1;
    }

    g_id = TIMERID_FIRST ;

    return 0;
}
void timer_destroy(void)
{
    struct signal_timer *pstimer = NULL;

    while(! list_empty((&g_signal_list)->next)){
        list_del((&g_signal_list)->next);
        pstimer = container_of((&g_signal_list)->next, struct signal_timer, list_timer);
        free(pstimer);
    }
}

void timer_printf(void *arg)
{
    if(arg){
        struct signal_timer *pstimer = (struct signal_timer*)arg;
        printf("timerid:%d, aim time: %ld:%ld\n", pstimer->id, pstimer->atv.tv_sec, pstimer->atv.tv_usec);
    } else {
        printf("timerid is %d\n", g_id);
    }
}
int main(int argc, char **argv)
{
    int tid1 = 0, tid2 = 0, tid3 = 0;
    int i = 0;

    signal(SIGPIPE, SIG_IGN);
    timer_init();

    tid1 = timer_add(2, 0, timer_printf, NULL);
    tid2 = timer_add(3, 0, timer_printf, NULL);
    tid3 = timer_add(5, 0, timer_printf, NULL);

    alarm(1);
    while(1){
        sleep(1);
        printf("sleep 1s\n");
        i++;
        if(i%3 == 0) timer_del(tid1, true);
        if(i%7 == 0) timer_del(tid2, true);
        if(i%9 == 0) timer_del(tid3, true);
    }

    timer_destroy();

    return 0;
}

运行:

timerid:102, aim time: 468486:907381
timerid:101, aim time: 468486:907380
timerid:100, aim time: 468486:907380
process SIGALRM, next time is 0:999678
sleep 1s
timerid:100, aim time: 468488:907380
process SIGALRM, next time is 0:998577
sleep 1s
timerid:101, aim time: 468489:907380
process SIGALRM, next time is 0:999371
sleep 1s
----delete timerid is 100
process SIGALRM, next time is 0:999003
sleep 1s
timerid:102, aim time: 468491:907381
process SIGALRM, next time is 0:998901
sleep 1s
timerid:101, aim time: 468492:907380
process SIGALRM, next time is 2:998319
sleep 1s
sleep 1s
----delete timerid is 101
sleep 1s
process SIGALRM, next time is 0:999768
sleep 1s
----delete timerid is 102
sleep 1s
sleep 1s
sleep 1s
sleep 1s

 

posted @ 2018-05-26 19:02  yuxi_o  阅读(307)  评论(0编辑  收藏  举报