libevent札记 - C语言也能实现多态

0.前言

在C++中,提供了虚函数来实现多态,libevent是用C 语言写的,在libevent中,这是通过函数指针来实现的。

1. 从IO复用封装看多态的实现

1.1 多态的关键

Libevent能够支持多种I/O多路复用技术来实现对事件的处理,关键在于结构体eventop,这个结构体的成员是一系列的函数指针, 定义在event-internal.h文件中:

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;
};

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

1.2 根据系统环境选择IO复用机制的优先级

全局静态数组 eventops中,数组内容根据优先级顺序声明:

#ifdef _EVENT_HAVE_POLL
    extern const struct eventop pollops;
#endif

#ifdef _EVENT_HAVE_EPOLL
    extern const struct eventop epollops;
#endif

/* In order of preference */
static const struct eventop *eventops[] = {
#ifdef _EVENT_HAVE_WORKING_KQUEUE
    &kqops,
#endif

#ifdef _EVENT_HAVE_EPOLL
    &epollops,
#endif

#ifdef _EVENT_HAVE_POLL
    &pollops,
#endif
#ifdef WIN32
    &win32ops,
#endif
    NULL
};

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

base->evbase = NULL;
for (i = 0; eventops[i] && !base->evbase; i++) {
    base->evsel = eventops[i];
    base->evbase = base->evsel->init(base);
}

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

const struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_add,
    epoll_del,
    epoll_dispatch,
    epoll_dealloc,
    1, /* need reinit */
    EV_FEATURE_ET|EV_FEATURE_O1,
    0
};

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

static void *epoll_init (struct event_base *);
static int epoll_add (void *, struct event *);
static int epoll_del (void *, struct event *);
static int epoll_dispatch(struct event_base *, void *, struct timeval *);
static void epoll_dealloc (struct event_base *, void *);

那么如果选择的是 epoll,那么调用结构体 eventop 的 init 和 dispatch 函数指针时,实际调用的函数就是 epoll 的初始化函数 epoll_init()和事件分发函数 epoll_dispatch()了;
同样的,上面 epollops 以及 epoll 的各种函数都直接定义在了 epoll.c 源文件中,对外都是不可见的。
对于 libevent 的使用者而言,完全不会知道它们的存在,对 epoll 的使用也是通过 eventop 来完成的,达到了信息隐藏的目的。

2 小节

首先是定义结构体eventop,结构体包含一系列的函数指针 –> 通过头文件根据系统环境选择相应的IO复用机制函数指针 –> 指向具体的IO复用机制函数
从上面可以看出,让libevent实现多态,支持多种 I/O 复用机制的方法通过借助于函数指针实现就 OK 了。
通过对源代码的分析也可以看出, Libevent 是在编译阶段选择系统的 I/O 复用 机制的,而不支持在运行阶段根据配置再次选择。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值