前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >libevent源码深度剖析十 支持I/O多路复用技术

libevent源码深度剖析十 支持I/O多路复用技术

作者头像
范蠡
发布2018-07-25 16:15:26
6990
发布2018-07-25 16:15:26
举报

系列目录

(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点

libevent的核心是事件驱动、同步非阻塞,为了达到这一目标,必须采用系统提供的I/O多路复用技术,而这些在Windows、Linux、Unix等不同平台上却各有不同,如何能提供优雅而统一的支持方式,是首要关键的问题,这其实不难,本节就来分析一下。

1.统一的关键

libevent支持多种I/O多路复用技术的关键就在于结构体eventop,这个结构体前面也曾提到过,它的成员是一系列的函数指针, 定义在event-internal.h文件中:

 1struct eventop {
 2    const char *name;
 3    void *(*init)(struct event_base *); // 初始化
 4    int (*add)(void *, struct event *); // 注册事件
 5    int (*del)(void *, struct event *); // 删除事件
 6    int (*dispatch)(struct event_base *, void *, struct timeval *); // 事件分发
 7    void (*dealloc)(struct event_base *, void *); // 注销,释放资源
 8    /* set if we need to reinitialize the event base */
 9    int need_reinit;
10};

在libevent中,每种I/O demultiplex机制的实现都必须提供这五个函数接口,来完成自身的初始化、销毁释放;对事件的注册、注销和分发。 比如对于epoll,libevent实现了5个对应的接口函数,并在初始化时并将eventop的5个函数指针指向这5个函数,那么程序就可以使用epoll作为I/O demultiplex机制了。

2.设置I/O demultiplex机制

libevent把所有支持的I/O demultiplex机制存储在一个全局静态数组eventops中,并在初始化时选择使用何种机制,数组内容根据优先级顺序声明如下:

 1/* In order of preference */
 2static const struct eventop *eventops[] = {
 3#ifdef HAVE_EVENT_PORTS
 4    &evportops,
 5#endif
 6#ifdef HAVE_WORKING_KQUEUE
 7    &kqops,
 8#endif
 9#ifdef HAVE_EPOLL
10    &epollops,
11#endif
12#ifdef HAVE_DEVPOLL
13    &devpollops,
14#endif
15#ifdef HAVE_POLL
16    &pollops,
17#endif
18#ifdef HAVE_SELECT
19    &selectops,
20#endif
21#ifdef WIN32
22    &win32ops,
23#endif
24    NULL
25}; 

然后libevent根据系统配置和编译选项决定使用哪一种I/O demultiplex机制,这段代码在函数event_base_new()中:

可以看出,libevent在编译阶段选择系统的I/O demultiplex机制,而不支持在运行阶段根据配置再次选择。

以Linux下面的epoll为例,实现在源文件epoll.c中,eventops对象epollops定义如下:

1const struct eventop epollops = {
2    "epoll",
3    epoll_init,
4    epoll_add,
5    epoll_del,
6    epoll_dispatch,
7    epoll_dealloc,
8    1 /* need reinit */
9};

变量epollops中的函数指针具体声明如下,注意到其返回值和参数都和eventop中的定义严格一致,这是函数指针的语法限制。

1static void *epoll_init    (struct event_base *);
2static int epoll_add    (void *, struct event *);
3static int epoll_del    (void *, struct event *);
4static int epoll_dispatch(struct event_base *, void *, struct timeval *);
5static void epoll_dealloc    (struct event_base *, void *);

那么如果选择的是epoll,那么调用结构体eventop的initdispatch函数指针时,实际调用的函数就是epoll的初始化函数epoll_init()和事件分发函数epoll_dispatch()了;

关于epoll的具体用法这里就不多说了,可以参见介绍epoll的文章: http://blog.csdn.net/sparkliang/archive/2009/11/05/4770655.aspx

C++语言提供了虚函数来实现多态,在C语言中,这是通过函数指针实现的。对于各类函数指针的详细说明可以参见文章: http://blog.csdn.net/sparkliang/archive/2009/06/09/4254115.aspx 同样的,上面epollops以及epoll的各种函数都直接定义在了epoll.c源文件中,对外都是不可见的。对于libevent的使用者而言,完全不会知道它们的存在,对epoll的使用也是通过eventop来完成的,达到了信息隐藏的目的。

3.小节

支持多种I/O demultiplex机制的方法其实挺简单的,借助于函数指针就OK了。通过对源代码的分析也可以看出,Libevent是在编译阶段选择系统的I/O demultiplex机制的,而不支持在运行阶段根据配置再次选择。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能服务器开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.统一的关键
  • 2.设置I/O demultiplex机制
  • 3.小节
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档