【網絡編程】處理定時事件(一)---模擬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();//處理到時事件,處理完成刪除事件
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章