在以前的文章裏咱們講過,libevent最後處理都是在event_base_loop調用了相應的dispatch函數,定時器也是在dispatch函數中處理的。網絡
仍是以epoll爲例,在epoll_dispatch函數有如下一段代碼:app
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的最後一個參數即爲超時時間 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的超時機制來實現定時器的,這樣咱們就能夠知道,其實定時器就是利用了select和epoll_wait等這些系統函數的超時機制,才實現的定時器。socket
總的來說,定時器就是在事件主循環中,等待網絡調用超時,當超時之後,將任務寫入隊列,而後處理隊列,調用回調函數,這樣就實現了定時器。函數
看libevent源代碼中例子:oop
#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); }
實現三秒調用一次回調函數,執行結果以下:spa
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.
文章同步發表在cpp加油站(ID:xy13640954449), 歡迎關注!