libevent實(shí)現(xiàn)定時(shí)器

1. 定時(shí)器是怎么實(shí)現(xiàn)的

在之前的文章里我們講過宏榕,libevent最后處理都是在event_base_loop調(diào)用了相應(yīng)的dispatch函數(shù),定時(shí)器也是在dispatch函數(shù)中處理的诡宗。

還是以epoll為例怀挠,在epoll_dispatch函數(shù)有以下一段代碼:

    if (tv != NULL) {
        timeout = evutil_tv_to_msec_(tv);
        if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
            /* Linux kernels can wait forever if the timeout is
             * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
            timeout = MAX_EPOLL_TIMEOUT_MSEC;
        }
    }

    epoll_apply_changes(base);
    event_changelist_remove_all_(&base->changelist, base);

    EVBASE_RELEASE_LOCK(base, th_base_lock);

    //epoll_wait的最后一個(gè)參數(shù)即為超時(shí)時(shí)間
    res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);

    EVBASE_ACQUIRE_LOCK(base, th_base_lock);

    if (res == -1) {
        if (errno != EINTR) {
            event_warn("epoll_wait");
            return (-1);
        }

        return (0);
    }

從上面代碼可以看出乃摹,是通過epoll_wait的超時(shí)機(jī)制來實(shí)現(xiàn)定時(shí)器的云茸,這樣我們就可以知道,其實(shí)定時(shí)器就是利用了select和epoll_wait等這些系統(tǒng)函數(shù)的超時(shí)機(jī)制妹萨,才實(shí)現(xiàn)的定時(shí)器年枕。

總的來講,定時(shí)器就是在事件主循環(huán)中乎完,等待網(wǎng)絡(luò)調(diào)用超時(shí)熏兄,當(dāng)超時(shí)以后,將任務(wù)寫入隊(duì)列树姨,然后處理隊(duì)列摩桶,調(diào)用回調(diào)函數(shù),這樣就實(shí)現(xiàn)了定時(shí)器帽揪。

2. 定時(shí)器代碼實(shí)現(xiàn)

看libevent源代碼中例子:

#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#include <time.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h>

struct timeval lasttime;

int event_is_persistent;

static void
timeout_cb(evutil_socket_t fd, short event, void *arg)
{
    struct timeval newtime, difference;
    struct event *timeout = (struct event*)arg;
    double elapsed;

    evutil_gettimeofday(&newtime, NULL);
    evutil_timersub(&newtime, &lasttime, &difference);
    elapsed = difference.tv_sec +
        (difference.tv_usec / 1.0e6);

    printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
        (int)newtime.tv_sec, elapsed);
    lasttime = newtime;

    if (! event_is_persistent) {
        struct timeval tv;
        evutil_timerclear(&tv);
        tv.tv_sec = 2;
        event_add(timeout, &tv);
    }
}

int
main(int argc, char **argv)
{
    struct event timeout;
    struct timeval tv;
    struct event_base *base;
    int flags;

    if (argc == 2 && !strcmp(argv[1], "-p")) {
        event_is_persistent = 1;
        flags = EV_PERSIST;
    } else {
        event_is_persistent = 0;
        flags = 0;
    }

    /* Initalize the event library */
    base = event_base_new();

    /* Initalize one event */
    event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);

    evutil_timerclear(&tv);
    tv.tv_sec = 3;
    event_add(&timeout, &tv);

    evutil_gettimeofday(&lasttime, NULL);

    event_base_dispatch(base);

    return (0);
}

實(shí)現(xiàn)三秒調(diào)用一次回調(diào)函數(shù)硝清,執(zhí)行結(jié)果如下:

timeout_cb called at 1535528104: 3.001 seconds elapsed.
timeout_cb called at 1535528107: 3.000 seconds elapsed.
timeout_cb called at 1535528110: 3.001 seconds elapsed.
timeout_cb called at 1535528113: 2.999 seconds elapsed.
timeout_cb called at 1535528116: 3.000 seconds elapsed.
timeout_cb called at 1535528119: 3.002 seconds elapsed.
timeout_cb called at 1535528122: 2.999 seconds elapsed.
timeout_cb called at 1535528125: 3.001 seconds elapsed.
timeout_cb called at 1535528128: 3.000 seconds elapsed.
timeout_cb called at 1535528131: 3.000 seconds elapsed.
timeout_cb called at 1535528134: 2.999 seconds elapsed.
timeout_cb called at 1535528137: 3.000 seconds elapsed.
timeout_cb called at 1535528140: 3.000 seconds elapsed.
timeout_cb called at 1535528143: 3.000 seconds elapsed.
timeout_cb called at 1535528146: 3.000 seconds elapsed.
timeout_cb called at 1535528149: 3.002 seconds elapsed.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市转晰,隨后出現(xiàn)的幾起案子芦拿,更是在濱河造成了極大的恐慌士飒,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔗崎,死亡現(xiàn)場離奇詭異酵幕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚁趁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門裙盾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來实胸,“玉大人他嫡,你說我怎么就攤上這事÷辏” “怎么了钢属?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長门躯。 經(jīng)常有香客問我淆党,道長,這世上最難降的妖魔是什么讶凉? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任染乌,我火速辦了婚禮,結(jié)果婚禮上懂讯,老公的妹妹穿的比我還像新娘荷憋。我一直安慰自己,他們只是感情好褐望,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布勒庄。 她就那樣靜靜地躺著,像睡著了一般瘫里。 火紅的嫁衣襯著肌膚如雪实蔽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天谨读,我揣著相機(jī)與錄音局装,去河邊找鬼。 笑死劳殖,一個(gè)胖子當(dāng)著我的面吹牛铐尚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闷尿,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼塑径,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了填具?” 一聲冷哼從身側(cè)響起统舀,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤匆骗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后誉简,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碉就,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年闷串,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓮钥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烹吵,死狀恐怖碉熄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肋拔,我是刑警寧澤锈津,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站凉蜂,受9級特大地震影響琼梆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜窿吩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一茎杂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纫雁,春花似錦煌往、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闲勺,卻和暖如春曾棕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背菜循。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工翘地, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人癌幕。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓衙耕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親勺远。 傳聞我的和親對象是個(gè)殘疾皇子橙喘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容