zoukankan      html  css  js  c++  java
  • libevent源码深度剖析十

    libevent源码深度剖析十

    ——支持I/O多路复用技术
    张亮

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

    1 统一的关键

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

    1. struct 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 */  
    2. static 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()中:

    1. base->evbase = NULL;  
    2.     for (i = 0; eventops[i] && !base->evbase; i++) {  
    3.         base->evsel = eventops[i];  
    4.         base->evbase = base->evsel->init(base);  
    5.     }   


        可以看出,libevent在编译阶段选择系统的I/O demultiplex机制,而不支持在运行阶段根据配置再次选择。
        以Linux下面的epoll为例,实现在源文件epoll.c中,eventops对象epollops定义如下:

    1. const 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中的定义严格一致,这是函数指针的语法限制。

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


          那么如果选择的是epoll,那么调用结构体eventop的init和dispatch函数指针时,实际调用的函数就是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机制的,而不支持在运行阶段根据配置再次选择。

  • 相关阅读:
    python 基础到字符串学习
    Newtonsoft.Json 获取匿名类数据
    Abp Wcf结合使用问题
    Ef Migration 操作出现SQLEXPRESS
    No context type was found in the assembly 'xxx.xxxx'. CodeFirst Ef错误
    Ef Code First 发生”provider: SQL Network Interfaces, error: 26
    ef 多条数据插入处理方案(据说还有更好的)
    记录一次 HttpWebRequest 尝试自动重定向太多 错误
    NetCore 下使用RSA加密,解密;并且前端使用jsencrypt.js实现Rsa相关方法。
    The specified framework version '2.0' could not be parsed 错误处理
  • 原文地址:https://www.cnblogs.com/breg/p/3725762.html
Copyright © 2011-2022 走看看