libevent實現(xiàn)定時器

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

在之前的文章里我們講過,libevent最后處理都是在event_base_loop調(diào)用了相應的dispatch函數(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的最后一個參數(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的超時機制來實現(xiàn)定時器的,這樣我們就可以知道,其實定時器就是利用了select和epoll_wait等這些系統(tǒng)函數(shù)的超時機制,才實現(xiàn)的定時器。

總的來講,定時器就是在事件主循環(huán)中,等待網(wǎng)絡調(diào)用超時,當超時以后,將任務寫入隊列,然后處理隊列,調(diào)用回調(diào)函數(shù),這樣就實現(xiàn)了定時器。

2. 定時器代碼實現(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);
}

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

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.
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容