libevent 事件的优先级队列
来源:互联网 发布:c语言数组合并 编辑:程序博客网 时间:2024/06/02 01:53
多个事件同时触发时,libevent没有定义各个回调函数的执行顺序。可以使用优先级来定义某些事件比其它事件更重要。
libevent里面的优先级队列就是active队列数组,当epoll返回event时,根据event对应的优先级放入队列的active数组列表中,实现了优先级的概念
1. event_Base的优先级队列libevent中,每个event_base都有与之相关的一个或者多个优先级。可以调用event_base_priority_init设置event_base的优先级数目。/*npriorities为多少,就代表要建多少个尾队列数组, * base->nactivequeues 表示数据个数 * base->activequeues表示数组首地址*/intevent_base_priority_init(struct event_base *base, int npriorities){ int i; if (N_ACTIVE_CALLBACKS(base) || npriorities < 1 || npriorities >= EVENT_MAX_PRIORITIES) return (-1); if (npriorities == base->nactivequeues) return (0); /*libevent里面的优先级队列就是active队列数组,当epoll返回event时,根据event对应的优先级放入队列的active数组列表中,实现了优先级的概念 * 这个优先队列是一个链表头数组,每一个链表头代表一个队列,nactivequeues代表队列的个数,activequeues数组的头指针*/ /* 这里为啥只要释放base->activequeues, 如果有多个队列怎么办? * 估计是默认只有一个优先级队列,所以此处只释放base->activequeues*/ if (base->nactivequeues) { mm_free(base->activequeues); base->nactivequeues = 0; } /*创建npriorities个优先队列*/ /* Allocate our priority queues */ base->activequeues = (struct event_list *) mm_calloc(npriorities, sizeof(struct event_list)); if (base->activequeues == NULL) { event_warn("%s: calloc", __func__); return (-1); } base->nactivequeues = npriorities; /*初始化队列头*/ for (i = 0; i < base->nactivequeues; ++i) { TAILQ_INIT(&base->activequeues[i]); } return (0);}
event的优先级
event的优先级默认是在创建event的时候初始化为base->nactivequeues/2.int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg){if (!base) base = current_base;_event_debug_assert_not_added(ev);ev->ev_base = base;.........if (base != NULL) { /* by default, we put new events into the middle priority */ ev->ev_pri = base->nactivequeues / 2;}_event_debug_note_setup(ev);return 0;}
也可以通过调用API event_priority_set 进行设置。
/* Set’s the priority of an event - if an event is already scheduled
- changing the priority is going to fail.
*/
- changing the priority is going to fail.
intevent_priority_set(struct event *ev, int pri){ _event_debug_assert_is_setup(ev); if (ev->ev_flags & EVLIST_ACTIVE) return (-1); if (pri < 0 || pri >= ev->ev_base->nactivequeues) return (-1); ev->ev_pri = pri; return (0);}
- 添加激活事件到优先队列
调用epoll_dipath将epoll_wait监测到的事件event通过evmap_io_active加入到优先队列。
static intepoll_dispatch(struct event_base *base, struct timeval *tv){ struct epollop *epollop = base->evbase; struct epoll_event *events = epollop->events; int i, res; long timeout = -1; 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); 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); } event_debug(("%s: epoll_wait reports %d", __func__, res)); EVUTIL_ASSERT(res <= epollop->nevents); for (i = 0; i < res; i++) { int what = events[i].events; short ev = 0; if (what & (EPOLLHUP|EPOLLERR)) { ev = EV_READ | EV_WRITE; } else { if (what & EPOLLIN) ev |= EV_READ; if (what & EPOLLOUT) ev |= EV_WRITE; } if (!ev) continue; evmap_io_active(base, events[i].data.fd, ev | EV_ET); } ....... return (0);}
evmap_io_active 通过fd索引对应的hash数组,找到对应event,再调用event_active_nolock将event加入优先队列
voidevmap_io_active(struct event_base *base, evutil_socket_t fd, short events){ struct event_io_map *io = &base->io; struct evmap_io *ctx; struct event *ev;#ifndef EVMAP_USE_HT EVUTIL_ASSERT(fd < io->nentries);#endif GET_IO_SLOT(ctx, io, fd, evmap_io); EVUTIL_ASSERT(ctx); TAILQ_FOREACH(ev, &ctx->events, ev_io_next) { if (ev->ev_events & events) event_active_nolock(ev, ev->ev_events & events, 1); }}
event_active_nolock调用event_queue_insert(base, ev, EVLIST_ACTIVE);
voidevent_active_nolock(struct event *ev, int res, short ncalls){ struct event_base *base; event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p", ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback)); /* We get different kinds of events, add them together */ if (ev->ev_flags & EVLIST_ACTIVE) { ev->ev_res |= res; return; } base = ev->ev_base; EVENT_BASE_ASSERT_LOCKED(base); ev->ev_res = res; if (ev->ev_pri < base->event_running_priority) base->event_continue = 1; if (ev->ev_events & EV_SIGNAL) {#ifndef _EVENT_DISABLE_THREAD_SUPPORT if (base->current_event == ev && !EVBASE_IN_THREAD(base)) { ++base->current_event_waiters; EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock); }#endif ev->ev_ncalls = ncalls; ev->ev_pncalls = NULL; } event_queue_insert(base, ev, EVLIST_ACTIVE); if (EVBASE_NEED_NOTIFY(base)) evthread_notify_base(base);}
通过取event的优先级,将event加入到对应的优先队列中
static voidevent_queue_insert(struct event_base *base, struct event *ev, int queue){ EVENT_BASE_ASSERT_LOCKED(base); if (ev->ev_flags & queue) { /* Double insertion is possible for active events */ if (queue & EVLIST_ACTIVE) return; event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already on queue %x", __func__, ev, EV_SOCK_ARG(ev->ev_fd), queue); return; } if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count++; ev->ev_flags |= queue; switch (queue) { ........ case EVLIST_ACTIVE: base->event_count_active++; TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri], ev,ev_active_next); break; ....... default: event_errx(1, "%s: unknown queue %x", __func__, queue); }}
- 最终调用event_process_active依次处理优先队列中的event
static intevent_process_active(struct event_base *base){ /* Caller must hold th_base_lock */ struct event_list *activeq = NULL; int i, c = 0; /*循环优先队列,保证了优先级高(数组索引值小)的队列先执行*/ for (i = 0; i < base->nactivequeues; ++i) { if (TAILQ_FIRST(&base->activequeues[i]) != NULL) { base->event_running_priority = i; activeq = &base->activequeues[i]; c = event_process_active_single_queue(base, activeq); if (c < 0) { base->event_running_priority = -1; return -1; } else if (c > 0) break; /* Processed a real event; do not * consider lower-priority events */ /* If we get here, all of the events we processed * were internal. Continue. */ } } event_process_deferred_callbacks(&base->defer_queue,&base->event_break); base->event_running_priority = -1; return c;}
最终调用event回调函数进行处理
static int event_process_active_single_queue(struct event_base *base, struct event_list *activeq){ struct event *ev; int count = 0; EVUTIL_ASSERT(activeq != NULL); for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { /*如果event是EV_PERSIST,只是将ev从active队列中移除, * 否者不是EV_PERSIST,则调用event_del_internal将ev从active 队列中移除,并从evmap_io或者evmap_signal中删除*/ if (ev->ev_events & EV_PERSIST) event_queue_remove(base, ev, EVLIST_ACTIVE); else event_del_internal(ev); if (!(ev->ev_flags & EVLIST_INTERNAL)) ++count; event_debug(( "event_process_active: event: %p, %s%scall %p", ev, ev->ev_res & EV_READ ? "EV_READ " : " ", ev->ev_res & EV_WRITE ? "EV_WRITE " : " ", ev->ev_callback));#ifndef _EVENT_DISABLE_THREAD_SUPPORT base->current_event = ev; base->current_event_waiters = 0;#endif switch (ev->ev_closure) { case EV_CLOSURE_SIGNAL: event_signal_closure(base, ev); break; case EV_CLOSURE_PERSIST: event_persist_closure(base, ev); break; default: case EV_CLOSURE_NONE: EVBASE_RELEASE_LOCK(base, th_base_lock); /*调用event回调函数*/ (*ev->ev_callback)( ev->ev_fd, ev->ev_res, ev->ev_arg); break; } EVBASE_ACQUIRE_LOCK(base, th_base_lock);#ifndef _EVENT_DISABLE_THREAD_SUPPORT base->current_event = NULL; if (base->current_event_waiters) { base->current_event_waiters = 0; EVTHREAD_COND_BROADCAST(base->current_event_cond); }#endif if (base->event_break) return -1; if (base->event_continue) break; } return count;}
阅读全文
0 0
- libevent 事件的优先级队列
- 优先级队列的使用
- 优先级的队列
- 队列的优先级
- 优先级队列的使用
- NSOperationQueue队列的优先级
- 优先级队列的实现
- 优先级队列的实现
- 优先级队列的使用
- 优先级队列的使用
- Python的优先级队列
- 利用优先级队列实现事件驱动模拟
- 试用libevent的事件触发
- libevent之事件的创立
- 优先级队列的一种用法
- 关于优先级队列的实现
- STL 优先队列的 优先级
- STL 优先队列的优先级
- 构建高性能.NET应用之配高可用IIS服务器-第五篇 IIS常见问题之:工作进程回收机制(中)
- [.NET Core].NET Core R2安装及示例教程
- 构建高性能.NET应用之配置高可用IIS服务器-第四篇 IIS常见问题之:工作进程回收机制(上)
- 构建高性能.NET应用之配置高可用IIS服务器-第三篇 IIS中三个核心组件的讲解(上)
- .NET Core 1.0 CentOS7 尝试
- libevent 事件的优先级队列
- 微软.NET 正式劈腿成功,横跨所有平台
- 构建高性能.NET应用之配置高可用IIS服务器-第二篇 IIS请求处理模型
- 关于Anaconda中修改Jupyter Notebook默认启动目录的问题
- C#在Linux上的开发指南
- 构建高性能.NET应用之配置高可用IIS服务器-第一篇:IIS必须掌握的知识
- 发布在即!.NET Core 1.0 RC2已准备就绪
- 利用记事本创建一个ASP.NET Core RC2 MVC应用
- Database Error (2002) notconnect