libevent 配置类详解

event_config_new 配置文件配置项

event_base_config_flagevent_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设置第二个flag

    enum 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如果做复制会有bug

    EVENT_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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值