您的位置:首页 > 编程语言 > C语言/C++

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

2017-08-22 13:46 330 查看

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 复用 机制的,而不支持在运行阶段根据配置再次选择。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: