【网络编程】处理定时事件(一)---模拟Redis实现(C++)

前言

最近学习了《高性能》定时器那章,而且看的Libco,Redis源码中都或多或少的需要处理定时事件,所以感觉写写Demo,记录一下避免遗忘。
目前想法是这个系列将分4篇,分别是按照Redis服务端处理定时事件,使用链表处理,使用时间轮处理(参照Libco实现),使用小顶堆处理。本文即为第一篇。

正文

感觉上,Redis中对于定时事件的处理并不精确,同时它的模型也最为简单,所以我就以它作为第一篇。
因为是开头,所以我们先介绍一下定时事件。

处理定时事件

在我们的服务端程序主要处理的便是两类事件,I/O事件和定时事件,当然,对于I/O事件,我们可以通过I/O多路复用较为高效的处理,而对于定时事件,如何精确地定时,组织事件和处理事件便是需要我们考虑的了。

Redis的定时事件

对于Redis定时事件的处理,在我之前的博客中有较为详细的分析,如果你对这部分并不清楚,请参照说说Redis的服务端设计,将Redis的处理流程理清。

简单来说,Redis定时事件实现(以epoll实现为例)如下:

定义一个定时器,维护一条定时器链表。
每个定时器包括了超时时间和回调函数,在链表中按照超时时间升序排列。

每次主循环,首先获取链表中最小超时时间t,也就是说t时间后将处理满足条件定时事件,然后传入epoll_wait。

epoll_wait返回后会有两种情况:
1.t未到便发生了I/O事件。
2.t到了无I/O事件发生。

返回后先处理I/O事件。然后再处理定时事件。
由于情况1我们会花费时间来处理I/O事件,所以我们处理定时事件的流程是先获取系统时间,然后遍历链表处理符合条件的事件(时间到了)。

我自己也用C++大概模拟了这个过程。(完整代码见我的github

/*回调函数*/
static int func(void *arg)
{
    std::cout << "ding dong! Now is  "<< time(NULL) << std::endl;
    return 1;
}

int main(void)
{
    /*定时事件链表,使用类模板实现*/
    TimerList<Timer> timerlist(5);


    Timer t,b;
    t.timeout = time(NULL) + 10; // 10s后到时
    t.doJob = func;              // 设置回调

    b.timeout = t.timeout + 5;   //15s后到时
    b.doJob = func;

    int timeout;
    /*初始化server*/
    Network server(5473);
    server.Listen();
    server.initMainLoop();

    /*添加定时事件*/
    timerlist.addEvent(t);
    timerlist.addEvent(b);

    while(!timerlist.isEmpty()){  // 如果队列不为空
        timeout = (timerlist.getLeastTimeout() - time(NULL) ) * 1000;// 获得最小超时事件
        server.startMainLoop(timeout);//内部封装epoll_wait
        timerlist.dealEvent();//处理到时事件,处理完成删除事件
    }

}
发布了75 篇原创文章 · 获赞 46 · 访问量 9万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览