之前就已经讲过IO模型,也大致讲了一下reactor模型。现在我们回到源码中,来看下IO复用在libevent中的具体使用。
之前说reactor的核心是事件驱动、同步非阻塞,这就需要采用IO多路复用。我们之前说过,libevent是跨平台的,也展示过他跨平台的技术。这节单独拿出来再聊一下。
eventop
struct eventop
{
const char *name;
void *(*init)(struct event_base *);//初始化
int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);//注册
int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);//删除
int (*dispatch)(struct event_base *, struct timeval *);//分发
void (*dealloc)(struct event_base *);//注销
int need_reinit;
enum event_method_feature features;
size_t fdinfo_len;
};
这部分代码我们曾在eventbase的介绍里看见过,其实这就是函数接口。多路分发其实就是这五个函数,初始化、注册、删除、分发、注销。在不同的平台可以根据不同的IO复用模型来提供自己的五个函数。
从五个函数可以看到,IO模型只需提供相应的函数指针就可以,然后将eventop指针指过去即可。这样就可以使用多路分发机制了。
libevent将多路分发机制存储在一个全局静态数组eventops中,在初始化时选择某机制。
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
};
举例的话可以回到第二篇看,就不再赘述,主要拿出来还是为了内容的一个连贯性,IO复用是一个比较核心的方法,所以也需要拿出来单独说一下。
libevent通过eventop这个结构体中的函数指针实现了多态,使用手法其实很像C++中的虚函数,所以如果改写为c++的版本,虚函数就可以在多路分发这里出现,通过虚函数的重载完成IO机制设置。
在分析源码的时候就开始往自己的语言上靠近,想象自己如果实现这个东西的话该怎么实现,源码的方法有没有改进之处。而不是一味的解读代码,就像之前说的,这个工作已经完成了,进行源码分析不是为了复现工作,而是在深入了解底层之后,能不能提高甚至重做这个工作,比这个更好,有思考才是源码分析的态度所在。