Libevent源码分析(二)——基本应用流程

前言

上一篇介绍了libevent的核心,Reactor模式,那么接下来,我们就用libevent来设置一个定时器,这样就可以更好的理解Reactor模式了。

设置定时器流程:

我们按步骤来解释,其实步骤就是建立Reactor各部分以及建立他们关系的过程,掌握了也就基本掌握了libevent的精髓,想想就刺激:

  1. 首先我们需要一个event_base的实例对象,也就是说我们需要先获得一个核心Reactor,使用event_init()函数即可:struct event_base * base = event_init();这样base就是一个Reactor,我们后续会具体介绍的。
  2. 我们需要初始化event,设置事件的回调函数,也就是我们Reactor模式中的event和event handle那一块,设置event就是要关联事件和句柄,然后再让event有一个回调函数。tips:回调函数就是一种,通过预留函数接口的方式,在以后去调用的手段,这也是libevent中一直在用的。
evtimer_set(&ev, timer_cb, NULL);
//事实上等价于调用了
event_set(&ev, -1, 0, timer_cb, NULL);
//函数原型:
void event_set(struct event *ev, int fd, short event, void (*cb)(int, 
short, void *), void *arg)

这里说一句,libevent中的都是比较复杂的结构体和指针,所以需要有一定的c语言功底。
ev:就是要初始化的event事件对象;
fd:事件绑定的“句柄”,对于信号事件,那就是信号
event:在该fd上关注的事件类型,可以是:EV_READ, EV_WRITE, EV_SIGNAL;分别是读写制类的
cb:当事件触发时,reactor会回调的函数,是一个函数指针,参数实际上就是,fd,event和自定义参数arg
arg:用户自定义的参数。
定时事件是不需要fd的,而且事件类型event是根据(event_add)的超时值设定的,所以这里也不用给。

整个第二步就是初始化一个event handle,事件类型保存在event结构体中。

  1. 注册事件到reactor,就是建立event和event_base的关系,event_base_set(base, &ev);
  2. 正式的去添加一个事件,有了前面的铺垫,我们现在可以添加了event_add(&ev, timeout);timeout是定时值,这一步对应到Reactor模式中就是建立Reactor和handle的关系,就是注册handle。当发生超时时间,Reactor就会调用回调函数了。
  3. 最后程序进入循环状态也就是event_base_dispatch(base);,这个就是时间分离器在这里等待,有我们关注的事件,就会调用回调函数。
struct event ev;
struct timeval tv;
void time_cb(int fd,short event, void* arg)
{
	printf("timer wakeup\n");
	event_add(&ev,&tv);//再次注册handle
}
int main()
{

	//设置超时时间
	tv.tv_sec = 10;//10s
	tv.tv_usec = 0;
	//1:
	struct event_base* base = event_init();
	//2:
	event_set(&ev,-1,0,time_cb,NULL);
	//evtimer_set(&ev,time_cb,NULL);
	//3:
	event_base_set(base,&ev);
	//4:
	event_add(&ev,&tv);
	//5:
	event_base_dispatch(base);

}

分析清楚了流程后,代码就非常清晰了,这就是基本的定时流程。

内部处理流程:

我们还是分析这一基本流程:

  1. 当应用程序注册一个event的时候,需要先初始化event,然后设置好回调函数以及触发事件的事件类型,对应于前面步骤的第二第三步;
  2. 然后需要向libevent的event demutiplexer添加该事件,也就是让它去帮我们监控该事件,对于我们这里的定时事件,libevent使用小根堆管理,会有一个key对应超时时间,对于信号和I/O事件则使用双向链表管理事件,具体实现,我们后续会在代码中继续剖析。
  3. 然后当事件已经被事件分离器管理以后,我们就可以调用event_base_dispatch(base)系列函数进入循环了,等待事件发生,就以select函数为例,每次循环之前,libevent就会去检查tv,然后设置select的超时时间,这样当select返回的时候,首先去检查超时事件,然后再去检查I/O,这样如果这是超时的话就可以达到定时的目的。
    libevent中事件有未决状态和激活状态,分别会放在不同的链表中,状态改变,本质就是从一个链表到另一个链表,然后去调用激活状态事件的回调函数。我找了一张图,大家可以理解一下:
    在这里插入图片描述
    总结:这个过程就是libevent对Reactor模式的实现

写在最后

讲到这里,其实对libevent的基本结构已经有了基本认识,后续无非对每一个模块的深入挖掘,一定要把前面的弄懂,反复理解,一定会有收获。

愿每一个程序员都能被温柔相待

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值