CppGuide社区 CppGuide社区
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
  • libevent源码深度剖析01
  • libevent源码深度剖析02
  • libevent源码深度剖析03
    • libevent源码深度剖析04
    • libevent源码深度剖析05
    • libevent源码深度剖析06
    • libevent源码深度剖析07
    • libevent源码深度剖析08
    • libevent源码深度剖析09
    • libevent源码深度剖析10
    • libevent源码深度剖析11
    • libevent源码深度剖析12
    • libevent源码深度剖析13
    • libevent源码深度剖析
    zhangxf
    2023-04-02
    目录

    libevent源码深度剖析03

    # libevent源码深度剖析03

    # libevent基本使用场景和事件流程

    # 1. 前言

    学习源代码该从哪里入手?我觉得从程序的基本使用场景和代码的整体处理流程入手是个不错的方法,至少从个人的经验上讲,用此方法分析libevent是比较有效的。

    # 2. 基本应用场景

    基本应用场景也是使用libevnet的基本流程,下面来考虑一个最简单的场景,使用livevent设置定时器,应用程序只需要执行下面几个简单的步骤即可。 1)首先初始化libevent库,并保存返回的指针

    struct event_base* base = event_init();
    
    1

    实际上这一步相当于初始化一个Reactor实例;在初始化libevent后,就可以注册事件了。

    2)初始化事件event,设置回调函数和关注的事件

    evtimer_set(&ev, timer_cb, NULL);
    
    1

    事实上这等价于调用 event_set(&ev, -1, 0, timer_cb, NULL); event_set的函数原型是:

    void event_set(struct event *ev, int fd, short event, void (*cb)(int, short, void *), void *arg)
    
    1

    ev:执行要初始化的event对象; fd:该event绑定的“句柄”,对于信号事件,它就是关注的信号; event:在该fd上关注的事件类型,它可以是EV_READ, EV_WRITE, EV_SIGNAL; cb:这是一个函数指针,当fd上的事件event发生时,调用该函数执行处理,它有三个参数,调用时由event_base负责传入,按顺序,实际上就是event_set时的fd, event和arg; arg:传递给cb函数指针的参数; 由于定时事件不需要fd,并且定时事件是根据添加时**(event_add)的超时值设定的,因此这里event也不需要设置。 这一步相当于初始化一个event handler**,在libevent中事件类型保存在event结构体中。 注意:libevent并不会管理event事件集合,这需要应用程序自行管理;

    3)设置event从属的event_base

    event_base_set(base, &ev); 
    
    1

    这一步相当于指明event要注册到哪个event_base实例上;

    4)是正式的添加事件的时候了

    event_add(&ev, timeout);
    
    1

    基本信息都已设置完成,只要简单的调用**event_add()函数即可完成,其中timeout是定时值; 这一步相当于调用Reactor::register_handler()**函数注册事件。

    5)程序进入无限循环,等待就绪事件并执行事件处理

    event_base_dispatch(base);
    
    1

    # 3. 实例代码

    上面例子的程序代码如下所示

    struct event ev;
    struct timeval tv;
    void time_cb(int fd, short event, void *argc){
        printf("timer wakeup/n");
        event_add(&ev, &tv); // reschedule timer
    }
    
    int main(){
        struct event_base *base = event_init();
        tv.tv_sec = 10; // 10s period
        tv.tv_usec = 0;
        evtimer_set(&ev, time_cb, NULL);
        event_add(&ev, &tv);
        event_base_dispatch(base);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 4. 事件处理流程

    当应用程序向libevent注册一个事件后,libevent内部是怎么样进行处理的呢?下面的图就给出了这一基本流程。 1)首先应用程序准备并初始化event,设置好事件类型和回调函数;这对应于前面第步骤2和3; 2)向libevent添加该事件event。对于定时事件,libevent使用一个小根堆管理,key为超时时间;对于Signal和I/O事件,libevent将其放入到等待链表(wait list)中,这是一个双向链表结构; 3)程序调用**event_base_dispatch()**系列函数进入无限循环,等待事件,以select()函数为例;每次循环前libevent会检查定时事件的最小超时时间tv,根据tv设置select()的最大等待时间,以便于后面及时处理超时事件; 当select()返回后,首先检查超时事件,然后检查I/O事件; Libevent将所有的就绪事件,放入到激活链表中; 然后对激活链表中的事件,调用事件的回调函数执行事件处理;

    # 5. 小结

    本节介绍了libevent的简单实用场景,并旋风般的介绍了libevent的事件处理流程,读者应该对libevent有了基本的印象,下面将会详细介绍libevent的事件管理框架(Reactor模式中的Reactor框架)做详细的介绍,在此之前会对源代码文件做简单的分类。

    编辑 (opens new window)
    上次更新: 2023/12/11, 22:32:09
    libevent源码深度剖析02
    libevent源码深度剖析04

    ← libevent源码深度剖析02 libevent源码深度剖析04→

    最近更新
    01
    第二章 关键字static及其不同用法
    03-27
    02
    第一章 auto与类型推导
    03-27
    03
    C++语言面试问题集锦 目录与说明
    03-27
    更多文章>
    Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式