event_config_new
配置文件配置项
event_base_config_flag
和event_config_set_flag
先看event_base_config_flag
-
按优先顺序排列的后端数组
static const struct eventop *eventops[] = { #ifdef EVENT__HAVE_EVENT_PORTS &evportops, #endif #ifdef EVENT__HAVE_WORKING_KQUEUE &kqops, #endif #ifdef EVENT__HAVE_EPOLL &epollops, #endif #ifdef EVENT__HAVE_DEVPOLL &devpollops, #endif #ifdef EVENT__HAVE_POLL &pollops, #endif #ifdef EVENT__HAVE_SELECT &selectops, #endif #ifdef _WIN32 &win32ops, #endif NULL };
IOCP,EPOLL POLL SELECT
依照前后优先级来进行底层调用
再看
event_config_set_flag
event_config_set_flag(struct event_config *cfg, int flag) { if (!cfg) return -1; cfg->flags |= flag; return 0; } //------------------------ struct event_config { TAILQ_HEAD(event_configq, event_config_entry) entries; int n_cpus_hint; struct timeval max_dispatch_interval; int max_dispatch_callbacks; int limit_callbacks_after_prio; enum event_method_feature require_features; enum event_base_config_flag flags; };
enum event_base_config_flag flags
设置第二个flagenum event_base_config_flag { EVENT_BASE_FLAG_NOLOCK = 0x01, EVENT_BASE_FLAG_IGNORE_ENV = 0x02, EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10, EVENT_BASE_FLAG_PRECISE_TIMER = 0x20 };
EVENT_BASE_FLAG_NOLOCK
不要为event_base分配锁,设置这个选项在于多进程或者单进程EVENT_BASE_FLAG_IGNORE_ENV
选择使用地后端不要检测`event *环境变量EVENT_BASE_FLAG_STARTUP_IOCP
仅用于windows启用任何必需的IOCP分发逻辑,还有一个需要设置地event_config_set_num_cpus_hint
地参数,来调优IOCP线程池,配置一下CPU的线程数量EVENT_BASE_FLAG_NO_CACHE_TIME
不是在事件循环每次准备执行超时回调,检测时间,会以浪费CPU为代价追求时间的精确性EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST
epoll下有效,防止同一个fd,多次激发,fd如果做复制会有bugEVENT_BASE_FLAG_PRECISE_TIMER
默认使用系统最快的记时机制,如果系统有较慢且更精确的则采用
关于配置参数特征的设定
enum event_method_feature {
EV_FEATURE_ET = 0x01,
EV_FEATURE_01 = 0x02,
EV_FEATURE_FDS = 0x04,
EV_FEATURE_EARLY_CLOSE = 0x08
};
EV_FEATURE_ET
边缘触发,只提醒一次
EV_FEATURE_FDS
要求支持任意文件描述符,比如file
示例代码
#include <iostream>
#include <event2/event.h>
#include <signal.h>
using namespace std;
int main()
{
if(signal(SIGPIPE,SIG_IGN) == SIG_ERR)
{
return 1;
}
event_config *conf = event_config_new();
// 设置任意支持文件描述符
event_config_require_features(conf,EV_FEATURE_FDS);
event_base* base = event_base_new_with_config(conf); // 创建上下文
event_config_free(conf);
event_base_free(base);
}
EV_FEATURE_01
添加、删除单个事件,或者确定哪个事件激活的操作
EV_FEATURE_EARLY_CLOSE
检测连接关闭
for (i = 0; eventops[i] && !base->evbase; i++) {
if (cfg != NULL) {
if (event_config_is_avoided_method(cfg,
eventops[i]->name))
continue;
if ((eventops[i]->features & cfg->require_features)
!= cfg->require_features)
continue;
}
//------
}
event_add
用于添加删除事件的函数
event_add(struct event *ev, const struct timeval *tv)
{
int res;
if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
event_warnx("%s: event has no event_base set.", __func__);
return -1;
}
EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
res = event_add_nolock_(ev, tv, 0);
EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
return (res);
}
EVUTIL_FAILURE_CHECK
一个宏,有个锁成员的操作的
event_add_nolock_
无锁添加事件
event_base_loop(base,EVLOOP_ONCE);
等待一个事件运行,直到没有活动事件就退出,可用于捕获信号
#include <iostream>
#include <event2/event.h>
#include <signal.h>
using namespace std;
static void Ctrl_C(int sock,short witch,void *arg)
{
cout<<"ctrl + c"<<endl;
}
int main()
{
event_base* base = event_base_new(); // 创建上下文
// 添加ctrl + c
event* csig = evsignal_new(base,SIGINT,Ctrl_C,base);
if(!csig)
{
cerr<<"sigint evsing new "<<endl;
return -1;
}
// 目前处于未决信号状态
// 事件的添加
if(event_add(csig,0)!=0)
{
cerr<<"sigint evsing ADD "<<endl;
return -1;
}
// 进入事件循环
event_base_dispatch(base);
event_base_free(base);
event_free(csig);
}
project(test)
cmake_minimum_required(VERSION 3.1)
include_directories(./)
aux_source_directory(. DIRSRCS)
add_executable(test ${DIRSRCS})
target_link_libraries(test pthread event event_pthreads)
event_add
参数2是一个定时器
int event_add(struct event *ev, const struct timeval *timeout)
struct timeval
{
__time_t tv_sec; /* Seconds. */
__suseconds_t tv_usec; /* Microseconds. 微妙*/
};
完全二叉树用于储存事件
添加和删除的性能是O(logN),辅以双向的链式队列,大量具有相同的超时值
event_base_init_common_timeout
存储事件的链表和定时器
struct common_timeout_list {
/* List of events currently waiting in the queue. */
struct event_list events;
/* 'magic' timeval used to indicate the duration of events in this
* queue. */
struct timeval duration;
/* Event that triggers whenever one of the events in the queue is
* ready to activate */
struct event timeout_event;
/* The event_base that this timeout list is part of */
struct event_base *base;
};
event_base_init_common_timeout(struct event_base *base,
const struct timeval *duration)
{
int i;
struct timeval tv;
const struct timeval *result=NULL;
struct common_timeout_list *new_ctl;
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (duration->tv_usec > 1000000) {
// 如果大于100万微妙
memcpy(&tv, duration, sizeof(struct timeval));
if (is_common_timeout(duration, base)) // 判断是否超时
tv.tv_usec &= MICROSECONDS_MASK; // 常见超时微秒掩码
tv.tv_sec += tv.tv_usec / 1000000; // 把秒划算成微妙
tv.tv_usec %= 1000000; // 把微妙计算成秒,会有精度问题
duration = &tv;
}
for (i = 0; i < base->n_common_timeouts; ++i) {
const struct common_timeout_list *ctl =
base->common_timeout_queues[i];
if (duration->tv_sec == ctl->duration.tv_sec &&
duration->tv_usec ==
(ctl->duration.tv_usec & MICROSECONDS_MASK)) {
EVUTIL_ASSERT(is_common_timeout(&ctl->duration, base));
result = &ctl->duration;
goto done;
}
}
if (base->n_common_timeouts == MAX_COMMON_TIMEOUTS) {
event_warnx("%s: Too many common timeouts already in use; "
"we only support %d per event_base", __func__,
MAX_COMMON_TIMEOUTS);
goto done;
}
if (base->n_common_timeouts_allocated == base->n_common_timeouts) {
int n = base->n_common_timeouts < 16 ? 16 :
base->n_common_timeouts*2;
struct common_timeout_list **newqueues =
mm_realloc(base->common_timeout_queues,
n*sizeof(struct common_timeout_queue *));
if (!newqueues) {
event_warn("%s: realloc",__func__);
goto done;
}
base->n_common_timeouts_allocated = n;
base->common_timeout_queues = newqueues;
}
new_ctl = mm_calloc(1, sizeof(struct common_timeout_list));
if (!new_ctl) {
event_warn("%s: calloc",__func__);
goto done;
}
TAILQ_INIT(&new_ctl->events);
new_ctl->duration.tv_sec = duration->tv_sec;
new_ctl->duration.tv_usec =
duration->tv_usec | COMMON_TIMEOUT_MAGIC |
(base->n_common_timeouts << COMMON_TIMEOUT_IDX_SHIFT);
evtimer_assign(&new_ctl->timeout_event, base,
common_timeout_callback, new_ctl);
new_ctl->timeout_event.ev_flags |= EVLIST_INTERNAL;
event_priority_set(&new_ctl->timeout_event, 0);
new_ctl->base = base;
base->common_timeout_queues[base->n_common_timeouts++] = new_ctl;
result = &new_ctl->duration;
done:
if (result)
EVUTIL_ASSERT(is_common_timeout(result, base));
EVBASE_RELEASE_LOCK(base, th_base_lock);
return result;
}