转载请注明出处: http://blog.csdn.net/luotuo44/article/details/38512719
event_base允许用户对它里面的event设置优先级,这样可以使得有些更重要的event能够得到优先处理。
Libevent实现优先级功能的方法是:用一个激活队列数组来存放激活event。即数组的元素是一个激活队列,所以有多个激活队列。并且规定不同的队列有不同的优先级。
可以通过event_base_priority_init函数设置event_base的优先级个数,该函数实现如下:
//event.c文件 int event_base_priority_init(struct event_base *base, int npriorities) { int i; //由N_ACTIVE_CALLBACKS宏可以知道,本函数应该要在event_base_dispatch //函数调用前调用。不然将无法设置。 if (N_ACTIVE_CALLBACKS(base) || npriorities < 1 || npriorities >= EVENT_MAX_PRIORITIES) return (-1); //之前和现在要设置的优先级数是一样的。 if (npriorities == base->nactivequeues) return (0); //释放之前的,因为N_ACTIVE_CALLBACKS,所以没有active的event。 //可以随便mm_free if (base->nactivequeues) { mm_free(base->activequeues); base->nactivequeues = 0; } //分配一个优先级数组。 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_base_dispatch函数会改动激活事件的个数,即会使得N_ACTIVE_CALLBACKS(base)为真。所以event_base_priority_init函数要在event_base_dispatch函数之前调用。此外要设置的优先级个数,要小于EVENT_MAX_PRIORITIES。这个宏是在event.h文件中定义,在2.0.21版本中,该宏被定义成256。在调用event_base_new得到的event_base只有一个优先级,也就是所有event都是同级的。
上面的代码调用mm_alloc分配了一个优先级数组。不同优先级的event会被放到数组的不同位置上(下面可以看到这一点)。这样就可以区分不同event的优先级了。以后处理event时,就可以从高优先级到低优先级处理event。
上面是设置event_base的优先级个数。现在来看一下怎么设置event的优先级。可以通过event_priority_set函数设置,该函数如下:
//event.c文件 int event_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); //pri值越小,其优先级就越高。 ev->ev_pri = pri; return (0); }在上面代码的第一个判断中,可以知道当event的状态是EVLIST_ACTIVE时,就不能对这个event进行优先级设置了。因此,如果要对event进行优先级设置,那么得在调用event_base_dispatch函数之前。因为一旦调用了event_base_dispatch,那么event就随时可能变成EVLIST_ACTIVE状态。
现在看一下一个event是怎么插入到event_base的优先级数组中。
//event.c文件 //event_active_nolock以event_queue_insert(base, ev, EVLIST_ACTIVE);方式调用 static void event_queue_insert(struct event_base *base, struct event *ev, int queue) { .... ev->ev_flags |= queue; //加入EVLIST_ACTIVE状态 switch (queue) { ... case EVLIST_ACTIVE: base->event_count_active++; //从优先级数组中找到对应的优先级 TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri], ev,ev_active_next); break; ... } }
最后,我们来看一下默认的event优先级是多少。想必大家都能想到这个默认优先级是在新建event结构体时设置的。不错,看下面的event_assign函数。
//event.c文件 由event_new函数调用本函数 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) { ... ev->ev_base = base; ev->ev_callback = callback; ev->ev_arg = arg; ev->ev_fd = fd; ev->ev_events = events; ev->ev_res = 0; ev->ev_flags = EVLIST_INIT; ev->ev_ncalls = 0; ev->ev_pncalls = NULL; .... if (base != NULL) { /* by default, we put new events into the middle priority */ ev->ev_pri = base->nactivequeues / 2;//默认优先级 } ... }在这个函数里面,对event的成员变量进行了一些设置。其中,优先级的设置值为优先级数组长度的一半,所以是中间优先级。