三 基本使用场景和事件流程

1  前言
学习源代码该从哪里入手?我觉得从程序的基本使用场景和代码的整体处理流程入手
是个不错的方法,至少从个人的经验上讲,用此方法分析 libevent 是比较有效的。
2  基本应用场景
基本应用场景也是使用 libevnet 的基本流程,下面来考虑一个最简单的场景,使用
livevent 设置定时器,应用程序只需要执行下面几个简单的步骤即可。
1)首先初始化 libevent 库,并保存返回的指针
struct event_base * base = event_init();
实际上这一步相当于初始化一个 Reactor 实例;在初始化 libevent 后,就可以注册事件了。
2)初始化事件 event,设置回调函数和关注的事件
evtimer_set(&ev, timer_cb, NULL);
事实上这等价于调用 event_set(&ev, -1, 0, timer_cb, NULL);

event_set 的函数原型是:

void event_set(struct event *ev, int fd, short event, void (*cb)(int,
short, void *), void *arg)
ev:执行要初始化的 event 对象;
fd:该 event 绑定的“句柄”,对于信号事件,它就是关注的信号;
event:在该 fd 上关注的事件类型,它可以是 EV_READ, EV_WRITE, EV_SIGNAL;
cb:这是一个函数指针,当 fd 上的事件 event 发生时,调用该函数执行处理,它有三个参数,
调用时由 event_base 负责传入,按顺序,实际上就是 event_set 时的 fd, event 和 arg;
arg:传递给 cb 函数指针的参数;
由于定时事件不需要 fd,并且定时事件是根据添加时(event_add)的超时值设定的,因此
这里 event 也不需要设置。
这一步相当于初始化一个 event handler,在 libevent 中事件类型保存在 event 结构体中。
注意:libevent 并不会管理 event 事件集合,这需要应用程序自行管理;
3)设置 event 从属的 event_base
event_base_set(base, &ev);
这一步相当于指明 event 要注册到哪个 event_base 实例上;
4)是正式的添加事件的时候了
event_add(&ev, timeout);

基本信息都已设置完成,只要简单的调用 event_add()函数即可完成,其中 timeout 是定时值;

这一步相当于调用 Reactor::register_handler()函数注册事件。

5)程序进入无限循环,等待就绪事件并执行事件处理

event_base_dispatch(base);

3  实例代码
上面例子的程序代码如下所示



struct event ev;
struct timeval tv;
void time_cb(int fd, short event, void *argc)
{
printf("timer wakeup\n");
event_add(&ev, &tv); // reschedule timer
}
int main()
{
struct event_base *base = event_init();
tv.tv_sec = 10; // 10s period
tv.tv_usec = 0;
evtimer_set(&ev, time_cb, NULL);
event_add(&ev, &tv);
event_base_dispatch(base);
}
4  事件处理流程
当应用程序向 libevent 注册一个事件后,libevent 内部是怎么样进行处理的呢?下面的
图就给出了这一基本流程。
1) 首先应用程序准备并初始化 event,设置好事件类型和回调函数;这对应于前面第步骤
2 和 3;
2) 向 libevent 添加该事件 event。对于定时事件,libevent 使用一个小根堆管理,key 为超
时时间;对于 Signal 和 I/O 事件,libevent 将其放入到等待链表(wait list)中,这是一
个双向链表结构;
3) 程序调用 event_base_dispatch()系列函数进入无限循环,等待事件,以 select()函数为例;
每次循环前 libevent 会检查定时事件的最小超时时间 tv,根据 tv 设置 select()的最大等
待时间,以便于后面及时处理超时事件;
当 select()返回后,首先检查超时事件,然后检查 I/O 事件;
11
Libevent 将所有的就绪事件,放入到激活链表中;

然后对激活链表中的事件,调用事件的回调函数执行事件处理;


5  小结
本节介绍了 libevent 的简单实用场景,并旋风般的介绍了 libevent 的事件处理流程,读
者应该对 libevent 有了基本的印象,下面将会详细介绍 libevent 的事件管理框架(Reactor 模
式中的 Reactor 框架)做详细的介绍,在此之前会对源代码文件做简单的分类。

猜你喜欢

转载自blog.csdn.net/c1523456/article/details/79583063