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.