在以前的文章里咱们讲过,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), 欢迎关注!