• 应用层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
    ", 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
    ", 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
    ", 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
    ", 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
    ", pstimer->id, pstimer->atv.tv_sec, pstimer->atv.tv_usec);
        } else {
            printf("timerid is %d
    ", 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
    ");
            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
  • 相关阅读:
    技术面试问题汇总第005篇:猎豹移动反病毒工程师part5
    技术面试问题汇总第004篇:猎豹移动反病毒工程师part4
    Hexo安装和配置
    hexo从零开始到搭建完整 转
    window下phpstudy的nginx配置虚拟主机
    CentOS Linux搭建SVN服务器
    解决CentOS7关闭/开启防火墙出现Unit iptables.service failed to load: No such file or directory.
    numpy使用
    Linux学习15_CentOS6.5下netcat工具安装教程
    中国天气网七天天气
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/9093990.html
Copyright © 2020-2023  润新知