event_base 结构

上一节我们具体分析了关于event结构, 其中涉及到了event_base所以本节就来分析与event同样重要的结构. event_base也就是Reactor模式中的反应器, 就是管理整个事件的注册, 删除等主要操作.

event_base结构

该结构在event-internal.h中.

struct event_base {
	const struct eventop *evsel;	// 选择事件的方法. 如epoll就调用关于epoll的几个函数
	void *evbase;	// 具体IO多路复用所需的成员, 定义成 void* 完全就是保证统一, 毕竟每一个IO多路复用需要参数的类型都可能不同
	// 注册的事件总数
	int event_count;		/* counts number of total events */
	// 就绪事件的总数
	int event_count_active;	/* counts number of active events */

	// 退出标识位,如果置为1了,那么就会退出事件主循环,为0则不会
	int event_gotterm;		/* Set to terminate loop */
	int event_break;		/* Set to terminate loop immediately */

	/* active event management */
	// 按优先级管理已经就绪的事件. 一级指针指向不同优先级,二级指针指向具体的事件,并形成链表结构.
	// 就绪事件 : 事件已经被触发, 但是还没有保额处理
	struct event_list **activequeues;
	// 优先级队列总数
	int nactivequeues;

	/* signal handling info */
	struct evsignal_info sig;	// 管理信号的成员

	struct event_list eventqueue;	// 添加事件到所有的 event 中
	struct timeval event_tv;	// 定时器

	struct min_heap timeheap;	// 小根堆的定时器

	struct timeval tv_cache;	// 用于与 event.ev_timeout 对比, 判断是否超时
};

是不是还是很懵逼, 这跟event一样有很多成员, 而且不同成员表示不同事件的处理. 这里还是以比较难以理解的进行解释吧, evselevbase我们下面具体分析.

  • event_gottermevent_break : 现在知道他们两个标志是让退出主循环就行了. (主循环后面分析, 这里先知道它就是libevet一直事件处理的地方).
  • event_countevent_count_active : 还记得event结构中有三个链表吗, 不记得可以回event结构看一下, 但是在event中链表的长度其实我们并不知道, 而他们的长度就在event_base这两个参数来判断的.
  • activequeues : 这是一个指向指针的指针, 也可以说是二维数组. 它用来保存事件以及确定事件的优先级. 比如 : *activequeues[1] 表示的就是优先级为 1 的链表. 一个事件的优先级在event结构中设置, 通过设置ev_pri. 所以一个事件的优先级所在链表就是 activequeues[event->ev_pri] .(这里大家不懂多理一下, 一定要理解).
  • nactivequeues : 表示activequeues设置的优先级个数. 如: nactivequeues = 2, 表示一共有两个优先级队列. 默认为 1.
  • sig : 像event一样, 对信号有特殊处理. (这个成员以后分析信号的时候再来分析)

以上成员解释现在最重要是弄清楚activequeues就行. 现在我们依照上一节的过程理一下event_base的处理过程.

  1. 事件注册 .

    如果事件被注册在event中并完成了对event结构初始化后, 接着将初始化event_base. 将event_count+1 . 如果事件是信号, 那么对结构中sig执行一系列操作(现在不必清楚); 如果事件设置了定时, 那么将它设置好结构中的定时器参数.

  2. 事件到来

    事件到来后将事件加入到event的就绪队列中同时将还要加入对应优先级队列activequeues链表中, event_count_active + 1 . 如果是定时的, 通过比较 event_base->tv_cacheevent->ev_timeout 比较是否超时, 超时则加入到就绪队列中.

反应器的接口函数

创建一个event_base对象就是创建一个新的libevent实例. 而前面也说到过Reactor的主要框架就是事件的注册, 删除等. 而这些功能的实现需要根据不同的IO多路复用函数不同处理, 但是尽管调用函数不同但是在libevent中都将他们融合成了统一的接口函数了. 他们分别是 :

int  event_add(struct event *ev, const struct timeval *timeout);	// 注册事件
int  event_del(struct event *ev);	// 删除事件
int  event_base_loop(struct event_base *base, int loops);	// 执行事件主循环
void event_active(struct event *event, int res, short events);	// 激活事件
void event_process_active(struct event_base *base); 	// 执行激活的事件

现在将他们展示出来就是希望你们能有一个主观上的了解, 以后分析至少能够联系其他有哪些功能函数.

eventop结构

咱们先来看一下eventop结构长什么样, 满足好奇心

// 选择具体某种 IO多路复用 来事件处理的结构
struct eventop {
	const char *name;
	void *(*init)(struct event_base *);	// 初始化
	int (*add)(void *, struct event *);	// 添加事件
	int (*del)(void *, struct event *);	// 删除事件
	int (*dispatch)(struct event_base *, void *, struct timeval *);	// 分发事件
	void (*dealloc)(struct event_base *, void *);	// 释放内存
	/* set if we need to reinitialize the event base */
	int need_reinit;
};

实际上eventop就是将我们几种IO多路复用(poll, epoll等)函数封装成统一的函数调用. 这些复用函数的选择是由libevent自动完成的. 这个现在有一个印象就行了, 以后分析IO多路复用时再来具体分析.

总结

本节咱们分析了event_base, 但是可能第一次看得时候还是不太清楚, 不要慌, 等你对libevent大致都看了一遍之后再回过头看这些脉络就清晰了. 下面我们就来分析反应器接口函数的部分函数实现.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值