相关文章推荐
酷酷的仙人球  ·  oracle ...·  1 年前    · 
沉稳的围巾  ·  How do I run multiple ...·  1 年前    · 

1. 简介

上一节中,我们学习了如何创建一个默认的event_base。但是在实际的应用中,默认的event_base是远远满足不了需求的。更多的时候我们是需要根据具体的使用情况,来建立一个复杂的event_base。关于如何建立复杂的event_base,其实在上一篇章中,我们已经提及。接下来我们将更深入的了解如何建立一个复杂的event_base。

2. event_base_new_with_config

建立一个复杂的event_base需要将设置好的event_config传递给event_base_new_with_config,该函数返回我们所需要的event_base。
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
	int i;
	struct event_base *base;
	int should_check_environment;
#ifndef EVENT__DISABLE_DEBUG_MODE
	event_debug_mode_too_late = 1;
#endif
	//调用内存管理函数分配event_base结构
	if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
		event_warn("%s: calloc", __func__);
		return NULL;
	if (cfg)
		base->flags = cfg->flags;	//设置flags标志
	//判断是否需要检查EVENT_ * 环境变量
	should_check_environment =
	    !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
		struct timeval tmp;
		int precise_time =
		    cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);	//是否设置了使用更精准的时间标志
		int flags;
		//如果没有设置使用更精准的时间标志,但是在环境变量中设置 使用更精准的时间那就设置标志
		if (should_check_environment && !precise_time) {
			precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;	//获取环境变量
			base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
		flags = precise_time ? EV_MONOT_PRECISE : 0;
		evutil_configure_monotonic_time_(&base->monotonic_timer, flags);	//配置是否使用更精准的时间
		gettime(base, &tmp);
	//初始化超时时间优先级队列(最小堆)
	min_heap_ctor_(&base->timeheap);
	base->sig.ev_signal_pair[0] = -1;
	base->sig.ev_signal_pair[1] = -1;
	//初始化socketpair,用于唤醒event_base通过其他线程
	base->th_notify_fd[0] = -1;
	base->th_notify_fd[1] = -1;
	//初始化队列
	TAILQ_INIT(&base->active_later_queue);
	evmap_io_initmap_(&base->io);
	evmap_signal_initmap_(&base->sigmap);
	event_changelist_init_(&base->changelist);
	base->evbase = NULL;
	//下面的这操作用于根据event_config进行设定
	if (cfg) {
		memcpy(&base->max_dispatch_time,
		    &cfg->max_dispatch_interval, sizeof(struct timeval));
		base->limit_callbacks_after_prio =
		    cfg->limit_callbacks_after_prio;
	} else {
		base->max_dispatch_time.tv_sec = -1;
		base->limit_callbacks_after_prio = 1;
	if (cfg && cfg->max_dispatch_callbacks >= 0) {
		base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;
	} else {
		base->max_dispatch_callbacks = INT_MAX;
	if (base->max_dispatch_callbacks == INT_MAX &&
	    base->max_dispatch_time.tv_sec == -1)
		base->limit_callbacks_after_prio = INT_MAX;
	//选择使用的后端方法
	for (i = 0; eventops[i] && !base->evbase; i++) {
		//根据event_config的配置,是否屏蔽某些后端或设置某项特征
		if (cfg != NULL) {
			/* determine if this backend should be avoided */
			if (event_config_is_avoided_method(cfg,
				eventops[i]->name))
				continue;
			if ((eventops[i]->features & cfg->require_features)
			    != cfg->require_features)
				continue;
		//环境变量的设置
		/* also obey the environment variables */
		if (should_check_environment &&
		    event_is_method_disabled(eventops[i]->name))
			continue;
		//找到要使用的后端
		base->evsel = eventops[i];
		base->evbase = base->evsel->init(base);
	//没找到可使用的后端,返回 NULL
	if (base->evbase == NULL) {
		event_warnx("%s: no event mechanism available",
		    __func__);
		base->evsel = NULL;
		event_base_free(base);
		return NULL;
	if (evutil_getenv_("EVENT_SHOW_METHOD"))
		event_msgx("libevent using: %s", base->evsel->name);
	/* allocate a single active event queue */
	if (event_base_priority_init(base, 1) < 0) {
		event_base_free(base);
		return NULL;
	/* prepare for threading */
#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
	event_debug_created_threadable_ctx_ = 1;
#endif
#ifndef EVENT__DISABLE_THREAD_SUPPORT
	//使能了线程的支持
	if (EVTHREAD_LOCKING_ENABLED() &&
	    (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
		int r;
		EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);
		EVTHREAD_ALLOC_COND(base->current_event_cond);
		//用于初始化通知
		r = evthread_make_base_notifiable(base);
		if (r<0) {
			event_warnx("%s: Unable to make base notifiable.", __func__);
			event_base_free(base);
			return NULL;
#endif
#ifdef _WIN32
	if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
		event_base_start_iocp_(base, cfg->n_cpus_hint);
#endif
	return (base);

2.1 evutil_configure_monotonic_time_

这个函数是用来配置使用时间精度精准或比较粗糙。通过是否设置了使用精准的时间标志选择。 evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base, int flags) /* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris. You need to * check for it at runtime, because some older kernel versions won't * have it working. */ #ifdef CLOCK_MONOTONIC_COARSE //内核是否支持CLOCK_MONOTONIC_COARSE const int precise = flags & EV_MONOT_PRECISE; #endif const int fallback = flags & EV_MONOT_FALLBACK; struct timespec ts; #ifdef CLOCK_MONOTONIC_COARSE //关于CLOCK_MONOTONIC_COARSE和POSIX中CLOCK_MONOTONIC类似,只不过是精度比较粗糙的版本 if (CLOCK_MONOTONIC_COARSE < 0) { /* Technically speaking, nothing keeps CLOCK_* from being * negative (as far as I know). This check and the one below * make sure that it's safe for us to use -1 as an "unset" * value. */ event_errx(1,"I didn't expect CLOCK_MONOTONIC_COARSE to be < 0"); //如果flag设置使用精准的时间,那么是不会调用下面的 if (! precise && ! fallback) { if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) { base->monotonic_clock = CLOCK_MONOTONIC_COARSE; return 0; #endif //CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响,方便用于两个事件的间隔 if (!fallback && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { base->monotonic_clock = CLOCK_MONOTONIC; return 0; if (CLOCK_MONOTONIC < 0) { event_errx(1,"I didn't expect CLOCK_MONOTONIC to be < 0"); base->monotonic_clock = -1; return 0;

2.2 gettime

这个函数用于获取一个timeval时间
/** Set 'tp' to the current time according to 'base'.  We must hold the lock
 * on 'base'.  If there is a cached time, return it.  Otherwise, use
 * clock_gettime or gettimeofday as appropriate to find out the right time.
 * Return 0 on success, -1 on failure.
static int
gettime(struct event_base *base, struct timeval *tp)
	//如果使能调试锁,那么会断言event_base是否持有锁,这边要求必须持有锁,没有则断言失败
	EVENT_BASE_ASSERT_LOCKED(base);	
	//如果时间有了缓存,直接返回。避免过多的时间获取调用
	if (base->tv_cache.tv_sec) {
		*tp = base->tv_cache;
		return (0);
	//会根据evutil_configure_monotonic_time_中设置的monotonic_clock 来选择是否
	//使用gettimeofday或clock_gettime获取得到tp
	if (evutil_gettime_monotonic_(&base->monotonic_timer, tp) == -1) {
		return -1;
	//宏CLOCK_SYNC_INTERVAL定义为5,这里的意思是5s更新一次libevent内部时间不同(可能使用gettimeofday或clock_gettime)
	if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL
	    < tp->tv_sec) {
		struct timeval tv;
		evutil_gettimeofday(&tv,NULL);
		evutil_timersub(&tv, tp, &base->tv_clock_diff);
		base->last_updated_clock_diff = tp->tv_sec;
	return 0;
 

3. 使用范例

#include <stdio.h>
#include <string.h>
#include <event2/event-config.h>
#include <event2/event.h> 
//cc -I/usr/local/include -o test main.cpp -L/usr/local/lib -levent
int main(void)
	struct event_base *pBase;
	struct event_config *pConfig;
	pConfig = event_config_new();
	//设置event_base_config_flag:不检测环境变量和使用更精准的定时器
	event_config_set_flag(pConfig, EVENT_BASE_FLAG_IGNORE_ENV | EVENT_BASE_FLAG_PRECISE_TIMER);
	//告诉event_base不使用epoll和poll后端方法
	event_config_avoid_method(pConfig, "epoll");
	event_config_avoid_method(pConfig, "poll");
	//对后端的特性进行筛选
	event_config_require_features(pConfig, EV_FEATURE_FDS);
	//设置CPU数
	event_config_set_num_cpus_hint(pConfig, 1);
	//设置事件优先级相关的
	event_config_set_max_dispatch_interval(pConfig, NULL, -1, 0);
	pBase = event_base_new_with_config(pConfig);
	if (pBase == NULL)
		fprintf(stderr, "event_base_new_with_config error!\r\n");
		event_config_free(pConfig);
		return 0;
	const char *pCurrMethod = event_base_get_method(pBase);
	if (pCurrMethod != NULL)
		printf("Current method is %s\r\n", pCurrMethod);
	//do something...
	event_config_free(pConfig);
	event_base_dispatch(pBase);
	event_base_free(pBase);
	return 0;
在Linux上运行如下所示:
Current method is select
event_base_new(void)
	struct event_base *base = NULL;                 // 初始化一个event_base 
	struct event_config *cfg = event_config_new();  // 看下文注解
	if (cfg) {
		base = event_base_new_with_config(cfg);  // 将event_conf
                                    一、编译构建
libevent是一个用c编写的高性能网络框架,通过简单的封装,就能构造自己的应用服务器,从https://libevent.org就能下载到相应的版本tar包。
因为我们要在linux系统中使用,所以找到一个linux环境,编译并使用它:
./configure --prefix=/root/libevent/libevent-2.1.12-stable
先用configure进制文件发起检查,没问题了就可以了。
然后进入cmake文件夹
cmake .. &&am
                                    0. 前言我使用的版本是libevent-2.0.21-stable。高级的应用还是得看官网文档http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/1. 编译1.1 Linux版编译在目录下./configure && make即可在./.lib/下得到5个.a静态库。 sdfsdfdsf
                                    libevent源码深度剖析三——libevent基本使用场景和事件流程张亮1 前言学习源代码该从哪里入手?我觉得从程序的基本使用场景和代码的整体处理流程入手是个不错的方法,至少从个人的经验上讲,用此方法分析libevent是比较有效的。2 基本应用场景基本应用场景也是使用libevnet的基本流程,下面来考虑一个最简单的场景,使用livevent设置定时器,应用程序只需要
                                    Libevent 编程- 定时器事件(timer event)本文介绍Libevent 三种事件之一的定时器事件。 该事件可以用来注册定时事件和周期性事件。Libevent 根据所有定时器事件的最小超时时间来设置系统 I/O 的 timeout 值,当系统I/O 返回时,再激活就绪的定时器事件,如此 Timer 事件便可融合在系统 I/O 机制中。
定时器事件的实现基于一种经典的数据结构-小根堆,相
作为一个底层的支持系统,UEFI没有支持中断。如果想支持异步操作,只能通过事件(Event)来实现。
在开发Foxdisk的过程中,也遇到需要同时处理的事件。比如提示用户输入的闪烁光标、自动显示的系统时间等,我是采用了时钟中断(int 1Ch)的方式来实现的,是段很有意思的程序。
不过,我只是简单地将需要的功能堆砌在int 1Ch中实现,并没有完整地实现多...