精华内容
下载资源
问答
  • 定时器设计

    2019-10-20 13:56:23
    然后程序延时任务时间-当前时间后,调用任务即可,对方对答案并不满意,但我也没搞懂他的需求和他想要的答案,最后不欢而散,参考以上文章总结多种定时器设计方法,其中又一个很好的方法,就是利用Linux中的crontab ...

    参考

    https://www.hifreud.com/2015/04/30/timer-design/

    https://zhuanlan.zhihu.com/p/38408679

    http://www.cppblog.com/expter/archive/2010/03/05/108977.aspx

    https://baijiahao.baidu.com/s?id=1646829697791625138&wfr=spider&for=pc&isFailFlag=1

    https://blog.csdn.net/Monster_ixx/article/details/88651721

    定时任务系统方案设计 https://blog.csdn.net/stpeace/article/details/65934925

    之前某在线教育公司面试的一个问题,问如何设计一个定时器,当时对方需求也不太明确,我问他具体需求,那哥们居然愣了,只是说设计一个定时器,到点执行任务,当时的想法比较简单,调用系统获取时间的函数,得知当前时间,然后程序延时任务时间-当前时间后,调用任务即可,对方对答案并不满意,但我也没搞懂他的需求和他想要的答案,最后不欢而散,参考以上文章总结多种定时器设计方法,其中又一个很好的方法,就是利用Linux中的crontab 命令来实现定时任务,其原理参考https://blog.csdn.net/coder_xia/article/details/60871082。其他的多任务的定时器,可以采用时间轮的方式。

    展开全文
  • 定时器设计门铃hex文件用定时器设计门铃hex文件用定时器设计门铃hex文件用定时器设计门铃hex文件用定时器设计门铃hex文件用定时器设计门铃hex文件
  • VBA定时器设计

    2012-12-04 01:04:04
    VBA定时器设计
  • 基于AVR单片机用定时器设计的门铃仿真设计资料
  • 名称:用定时器设计的门铃 说明:按下按键时蜂鸣器发出叮咚的门铃声。
  • 定时器设计门铃

    2014-04-20 12:55:58
    定时器设计门铃 源程序+仿真文件 单片机仿真 定时器的应用
  • 单片机程序控制定时器设计.pdf
  • 定时器设计(一)

    2021-06-05 22:14:12
    定时器前言一、定时器设计二、基于排序链表的定时器设计1.设计介绍2.基于时间轮的定时器设计总结参考 前言 客户端与服务器通过socket进行连接和通信,但是socket有限的,非活跃连接占用了连接资源,对服务器的性能...


    前言

    客户端与服务器通过socket进行连接和通信,但是socket有限的,非活跃连接占用了连接资源,对服务器的性能影响很大,通过设计服务器定时器来处理非活跃连接,释放连接资源。


    一、定时器设计

    定时器的设计包括基于小根堆的定时器、基于排序链表的定时器、基于时间轮的定时器。本文主要介绍基于排序链表的定时器和基于时间轮的定时器。

    定时器是将所需的定时事件封装起来,本文主要是将检测非活跃连接封装成一个定时器。

    定时器回调函数:从内核事件表删除事件,关闭文件描述符,释放连接资源。

    void cb_func(client_data *user_data)
    {   //删除非活动连接在socket上的注册事件
        epoll_ctl(Utils::u_epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0);
        assert(user_data);
        //关闭文件描述符
        close(user_data->sockfd);
        //减少连接数
        http_conn::m_user_count--;
    }
    

    连接资源主要包括 客户端套接字地址、文件描述符、定时器。

    class util_timer;
    
    struct client_data
    {
        sockaddr_in address;
        int sockfd;
        util_timer *timer;
    };
    

    1、基于排序链表定时器设计

    基于排序链表的类包括超时时间、回调函数、连接资源、前向定时器、后继定时器。

    class util_timer
    {
    public:
        util_timer() : prev(NULL), next(NULL) {}
    
    public:
        time_t expire;
        
        void (* cb_func)(client_data *);
        client_data *user_data;
        util_timer *prev;
        util_timer *next;
    };
    

    2、基于时间轮定时器设计

    基于时间轮的定时器类包括时间轮圈数、时间轮的槽、回调函数、连接资源、前向定时器、后继定时器。

    class util_timer
    {
    public:
        util_timer(int rot ,int ts) : prev(NULL), next(NULL),rotation(rot),time_slot(ts) {}
    
    public:
        // 时间轮圈数
        int rotation;
        // 时间轮的槽
        int time_slot;
        //回调函数:从内核事件表删除事件,关闭文件描述符,释放连接资源
        void (* cb_func)(client_data *);
        //连接资源
        client_data *user_data;
        //前向定时器
        util_timer *prev;
        //后继定时器
        util_timer *next;
    };
    

    二、定时器容器设计

    1、基于排序链表的定时器设计

    基于排序链表定时器设计,是利用alarm函数周期触发SIGALRM信号,信号处理函数通过管道通知主循环对排序链表的定时器进行处理。
    定时器容器为升序双向链表,按照超时时间升序排列,根据触发信号定时将到期的定时信号从链表中删除。
    升序双向链表的主要成员函数如下:

    class sort_timer_lst
    {
    public:
        sort_timer_lst();
        ~sort_timer_lst();
    
        void add_timer(util_timer *timer);
        void adjust_timer(util_timer *timer);
        void del_timer(util_timer *timer);
        void tick();
    
    private:
        void add_timer(util_timer *timer, util_timer *lst_head);
    
        util_timer *head;
        util_timer *tail;
    };
    

    1.add_timer函数,将定时器添加到链表中,如果当前链表中没有其他定时器那么直接插入链表,否则将定时器根据超时时间升序插入。

    void add_timer(util_timer *timer)
    {
       if (!timer)
       {
           return;
       }
       if (!head)
       {
           head = tail = timer;
           return;
       }
        if (timer->expire < head->expire)
       {
           timer->next = head;
           head->prev = timer;
           head = timer;
           return;
       }
       add_timer(timer, head);// 此处的add_timer函数并不是递归,因为参数数量不同,该处的add_timer函数为重载函数(如下定义)。
    }
    

    包含两个参数的add_timer函数,主要用于包含一个参数的add_timer函数和adjust_timer函数调用。

    void add_timer(util_timer *timer, util_timer *lst_head)
    {
       util_timer *prev = lst_head;
       util_timer *tmp = prev->next;
       while (tmp)
       {
           if (timer->expire < tmp->expire)
           {
               prev->next = timer;
               timer->next = tmp;
               tmp->prev = timer;
               timer->prev = prev;
               break;
           }
           prev = tmp;
           tmp = tmp->next;
       }
       if (!tmp)
       {
           prev->next = timer;
           timer->prev = prev;
           timer->next = NULL;
           tail = timer;
       }
    }
    

    2.adjust_timer函数:当定时器的超时时间发生变化时,需要调整定时器在链表中的位置。当客户端在超时时间内进行数据收发,则需要重新设置定时器的超时时间。如果定时器在链表尾部无需调整定时的位置,否则需要将定时器从链表中取出,并且重新插入链表。

    void adjust_timer(util_timer *timer)
    {
       if (!timer)
       {
           return;
       }
       util_timer *tmp = timer->next;
       if (!tmp || (timer->expire < tmp->expire))
       {
           return;
       }
       if (timer == head)
       {
           head = head->next;
           head->prev = NULL;
           timer->next = NULL;
           add_timer(timer, head);
       }
       else
       {
           timer->prev->next = timer->next;
           timer->next->prev = timer->prev;
           add_timer(timer, timer->next);
       }
    }
    

    3.del_timer函数:将超时的定时器从链表中删除。

    void del_timer(util_timer *timer)
    {
        if (!timer)
        {
            return;
        }
        if ((timer == head) && (timer == tail))
        {
            delete timer;
            head = NULL;
            tail = NULL;
            return;
        }
        if (timer == head)
        {
            head = head->next;
            head->prev = NULL;
            delete timer;
            return;
        }
        if (timer == tail)
        {
            tail = tail->prev;
            tail->next = NULL;
            delete timer;
            return;
        }
        timer->prev->next = timer->next;
        timer->next->prev = timer->prev;
        delete timer;
    }
    

    4.定时处理任务函数:
    使用统一事件源,SIGALRM信号每次被触发,主循环调用一次定时任务处理函数,处理链表中到期的定时器。
    遍历定时器升序链表容器,从头结点开始依次处理每个定时器,若当前时间大于定时器超时时间,即找到了到期的定时器,执行回调函数,然后将其从链表中删除,然后继续遍历,若当前时间小于定时器超时时间,则跳出循环停止遍历。

    void tick()
    {
        if (!head)
        {
            return;
        }
        
        time_t cur = time(NULL);
        util_timer *tmp = head;
        while (tmp)
        {
            if (cur < tmp->expire)
            {
                break;
            }
            tmp->cb_func(tmp->user_data);
            head = tmp->next;
            if (head)
            {
                head->prev = NULL;
            }
            delete tmp;
            tmp = head;
        }
    }
    
    

    定时器的使用:
    客户端与服务器连接时,创建该连接对应的定时器,并且将定时器添加到链表上。
    处理异常事件时,执行定时事件,服务器关闭连接,并且将定时器从链表中移除。
    如果某个连接上发生了读写事件,则将对应的定时器向后移动。

    2、基于时间轮的定时器设计

    时间轮模型如下:

    时间轮模型
    时间轮定时器主要解决升序链表插入效率比较低的问题。
    指针指向时间轮的一个槽(slot),以恒定速度顺时针转动,每转动一步指针就指向下一个槽。每次转动称为一个tick。一个tick的时间称为时间轮的槽间隔si(slot interval)。时间轮一共有N个槽,所以它运转一周的时间是 N ∗ s i N*si Nsi(N和si的值都是可以人为设置的)。每个槽指向一条定时器链表,链表上的定时器定时时间相差 N ∗ s i N*si Nsi的整数倍。假如现在指针指向槽cs,添加一个定时时间为ti的定时器,则该定时器将被插入槽ts对应的链表中:
    t s = ( c s + ( i / s i ) ) % N ts=(cs+(i/si))\%N ts=(cs+(i/si))%N r o t a t i o n = t i c k s / N rotation = ticks / N rotation=ticks/N
    对于时间轮而言,要提高定时精度,就要使si值足够小;要提高执行效率,则要N值足够大。
    时间轮主要成员函数如下:

    //时间轮
    class time_wheel
    {
    public:
        time_wheel();
        ~time_wheel();
        util_timer* add_timer(int timeout);
        void del_timer(util_timer* timer);
        void tick();
    private:
        //时间轮上的槽数
        static const int N = 60;
        //槽间隔,
        static const int SI = 1;
        //时间轮的槽,其中的元素指向定时器的链表
        util_timer* slots[N];
        int cur_slot;
    };
    

    1.add_timer函数:根据给出的超时时间和当前所指向的时间槽,计算出定时器的圈数rotation和对应的时间槽slot。直接将定时器添加到对应槽链表的头部。

    util_timer* add_timer(int timeout) {
        if (timeout < 0)
            return nullptr;
    int ticks = 0;
      if (timeout < SI) {
        ticks = 1;
    }
    else{
        ticks = timeout / SI;
    }
    int rotation = ticks / N;
    int ts = (cur_slot + (ticks % N)) % N;
    //创建新的定时器
    util_timer* timer = new util_timer(rotation, ts);
    if (!slots[ts]) {
        printf("rotation is %d,ts is %d,cur_slot is %d\n", rotation, ts, cur_slot);
        slots[ts] = timer;
    }
    else {
        timer->next = slots[ts];
        slots[ts]->prev = timer;
        slots[ts] = timer;
    }
    return timer;
    }
    

    2.adjust_timer函数:将定时器从之前槽对应的链表上删除,并且重新计算定时器的时间轮圈数和对应的时间槽,并将定时器添加到对应槽链表的头部。

    void adjust_timer(util_timer* timer,const int TIMESLOT){
        if(!timer)
        return ;
        int ts = timer->time_slot;
        if(timer==slots[ts]){
          slots[ts] = timer->next;
          if(timer->next){
              timer->next->prev = nullptr;
          }
      
        }
      else {
            timer->prev->next = timer->next;
            if (timer->next) {
                timer->next->prev = timer->prev;
            }
        }
        timer->rotation=3 * TIMESLOT/SI/N;
        timer->time_slot =  (cur_slot +((3 * TIMESLOT/SI)%N))%N;//我感觉这块是有问题的 
        int ts1 = timer->time_slot;
        int rotation1 = timer->rotation;
        if (!slots[ts1]) {
        printf("rotation is %d,ts is %d,cur_slot is %d\n", rotation1, ts1, cur_slot);
        slots[ts1] = timer;
    }
    else {
        timer->next = slots[ts1];
        slots[ts1]->prev = timer;
        slots[ts1] = timer;
        timer-> prev = nullptr ;
    }  
    
    }
    

    3.del_timer函数:将对应槽上的定时器删除。

    void del_timer(util_timer* timer) {
        if (!timer)
            return;
        int ts = timer->time_slot;
        if (timer == slots[ts]) {
            slots[ts] = slots[ts]->next;
            if (slots[ts]) {
                slots[ts]->prev = nullptr;
            }
        }
        else {
            timer->prev->next = timer->next;
            if (timer->next) {
                timer->next->prev = timer->prev;
            }
        }
        delete timer;
    }
    

    4.定时处理任务函数:
    使用统一事件源,SIGALRM信号每次被触发,主循环调用一次定时任务处理函数,相当于时间轮转动一次,并且处理当前时间槽对应的链表。
    遍历时间槽对应的链表,从头结点开始依次处理每个定时器,若当前定时器的圈数大于0,那么将当前圈数减一,并且继续遍历链表,如果当前定时器的圈数为0,即找到了到期的定时器,执行回调函数,然后将它链表中删除,然后继续遍历,直到将整个链表遍历完。

    void tick() {
        util_timer* tmp = slots[cur_slot];
        printf("current slot is %d\n", cur_slot);
        while (tmp) {
            printf("tick the timer once\n");
            if (tmp->rotation > 0) {
                tmp->rotation--;
                tmp = tmp->next;
            }
            else {
                tmp->cb_func(tmp->user_data);
                if (tmp == slots[cur_slot]) {
                    printf("delete header in cur_slot\n");
                    slots[cur_slot] = tmp->next;
                    delete tmp;
                    if (slots[cur_slot]) {
                        slots[cur_slot]->prev = nullptr;
                    }
                    tmp = slots[cur_slot];
                }
                else {
                    tmp->prev->next = tmp->next;
                    if (tmp->next) {
                        tmp->next->prev = tmp->prev;
                    }
                    util_timer* tmp2 = tmp->next;
                    delete tmp;
                    tmp = tmp2;
    
                }
            }
    
            }
        cur_slot =( ++cur_slot )% N;
        }
    

    定时器的使用:
    客户端与服务器连接时,创建该连接对应的定时器,并且将定时器添加到对应时间槽链表上。
    处理异常事件时,执行定时事件,服务器关闭连接,并且将定时器从对应时间槽链表中移除。
    如果某个连接上发生了读写事件,则将对应的定时器更换时间槽。


    总结

    1.遇到的问题

    在设计时间轮的时候,利用数组设计时间槽,很有可能会出现数组越界的可能,会导致段错误。

    2. 存在的不足

    时间轮的链表无需用双向链表实现,可以只用单向链表就能实现。

    参考

    《Linux高性能服务器编程》游双著
    基于排序链表的定时器设计主要参考:最新版Web服务器项目详解

    展开全文
  • verilog微波炉定时器设计
  • 基于FPGA的串行定时器设计.pdf
  • 单片机电子定时器设计 制作一个实时时钟,并且可以设置在某时间内对某一电器实行操作控制。
  • 51单片机定时器设计实验
  • 基于单片机技术的专用定时器设计及制作.pdf
  • 基于单片机的多功能定时器设计与实现.doc
  • Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现
  • 基于FPGA的任务管理器和定时器设计.pdf
  • 基于quartus的分频器和定时器设计
  • 555定时器设计软件

    2011-05-05 12:41:12
    555芯片定时器设计软件,这个软件简单易使用,有一定价值。
  • 基于MCS-51单片机的数字式定时器设计.pdf
  • 智能定时器设计 摘要定时器的数字化给人们生产生活带来了极大的方便同时定时器的集成化受 广大消费的喜爱 因此得到了广泛的使用 定时器是采用数字电路实现对时分秒数字显示的计时装置定时器 的精度稳定度远远超过...
  • 基于单片机的短跑定时器设计与实现 该项目包括原理图电路图 程序源码 演示视频讲解文档全套资料 三分拿去 超值了
  • 51/52单片机 用定时器设计的门铃 有仿真图和程序
  • 蓝桥杯单片机——09 定时器设计秒表,这个是我学习蓝桥杯单片机时,通过B站上的各种视频资源整理出来的代码。 J5接2、3,利用定时器T0、数码管模块和2个独立按键设计秒表: 1.显示格式: 分-秒-0.05秒(即50ms) 08-...
  • 数电课设——555定时器设计数字时钟

    千次阅读 多人点赞 2019-12-30 07:01:59
    熬夜做课设,写出来的东西,真香数电课设——555定时器设计数字时钟 数电课设——555定时器设计数字时钟 链接: link.

    熬夜做课设,写出来的东西,真香

    数电课设——555定时器设计数字时钟


    链接: link.

    展开全文
  • 人们经常忘记拔掉电源,更有甚者给电池充电达数天,这对电池的功能和使用寿命无疑是一种破坏。介于此,笔者萌生了自己动手设计制作一个数显可调定时器的想法,来解决一些生活中的问题。
  • 555定时器设计

    2013-04-05 16:27:06
    555定时器设计软件工具,适用范围广,应用多,好,非常好
  • 为了实现基于UDP网络的可靠通信,本文利用VxWorks的多种任务间通信机制和看门狗定时器机制,设计了一种多重定时器模型,该模型可以确保数据包的可靠传递。  1 VxWOrks的时钟及定时器机制  1.1 VxWorks延时函数 ...
  • 基于linux下的高精度定时器设计 编译运行 定时器运行结果 工程代码:

    基于linux下的高精度定时器设计

    工程文件

    编译运行
    在这里插入图片描述

    • 定时器运行结果
      在这里插入图片描述

    工程代码:
    工程文件

    展开全文
  • 基于STC89C52单片机的智能定时器设计 摘要定时器的数字化给人们生产生活带来了极大的方便同时定时器的集成化受广大消费的喜爱 因此得到了广泛的使用 定时器是采用数字电路实现对时分秒数字显示的计时装置定时器的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 85,860
精华内容 34,344
关键字:

定时器设计