🔑 核心概念与API - libevent源码深度解析系列(四)

2295 字
11 分钟
🔑 核心概念与API - libevent源码深度解析系列(四)

🧠 核心概念与API#

一、事件编程模型#

在事件驱动编程模型中,主要有三个核心组件:

  • 🔷 事件源(Event Source):产生事件的对象,如网络连接、文件描述符等。
  • 🔷 事件处理器(Event Handler):负责处理事件的回调函数。
  • 🔷 事件循环(Event Loop):负责调度事件处理器的中心组件。

1.1 事件驱动模型流程图#

┌─────────────────────────────────────────────────────────┐
│ 事件循环 (event_base) │
├─────────────────────────────────────────────────────────┤
│ 1. 初始化事件基 │
│ 2. 注册事件 (event_new + event_add) │
│ 3. 进入事件循环 (event_base_dispatch) │
│ ├─ 等待事件触发 │
│ ├─ 分发事件到对应的处理器 │
│ ├─ 执行事件回调 │
│ └─ 重复上述步骤 │
│ 4. 退出事件循环 │
└─────────────────────────────────────────────────────────┘

1.2 事件处理流程#

┌─────────────────────────────────────────────────────────┐
│ 事件处理流程 │
├─────────────────────────────────────────────────────────┤
│ 1. 事件源产生事件 (如网络数据到达) │
│ 2. I/O多路复用机制检测到事件 │
│ 3. event_base获取就绪事件 │
│ 4. 查找对应的event结构体 │
│ 5. 将event添加到活跃事件队列 │
│ 6. 按优先级处理活跃事件 │
│ 7. 调用事件的回调函数 │
│ 8. 如果是持久事件(EV_PERSIST),重新添加到事件队列 │
└─────────────────────────────────────────────────────────┘

二、事件基(Event Base)#

在 libevent 中,事件基(Event Base)是一个核心概念,它是事件驱动编程模型中的事件循环的实现。事件基负责管理所有注册的事件,并在事件发生时调度相应的事件处理器。

2.1 主要功能#

  • 🔶 事件注册:将事件注册到事件基
  • 🔶 事件调度:在事件发生时调度相应的事件处理器
  • 🔶 事件循环:通过 event_base_dispatch() 启动事件循环,处理事件

2.2 event_base_new API 详解#

struct event_base *event_base_new(void);

返回值#

  • 成功:返回事件基结构体指针
  • 失败:返回 NULL

2.3 event_base_new_with_config API 详解#

struct event_base *event_base_new_with_config(const struct event_config *cfg);

参数说明#

参数类型说明
cfgconst struct event_config*事件基配置结构体

返回值#

  • 成功:返回事件基结构体指针
  • 失败:返回 NULL

2.4 event_base_dispatch API 详解#

int event_base_dispatch(struct event_base *base);

参数说明#

参数类型说明
basestruct event_base*要启动的事件基

返回值#

  • 成功:返回 0
  • 失败:返回 -1

2.5 event_base_loop API 详解#

int event_base_loop(struct event_base *base, int flags);

参数说明#

参数类型说明
basestruct event_base*要启动的事件基
flagsint循环标志,如 EVLOOP_ONCE、EVLOOP_NONBLOCK 等

返回值#

  • 成功:返回 0
  • 失败:返回 -1

2.6 event_base_loopexit API 详解#

int event_base_loopexit(struct event_base *base, const struct timeval *tv);

参数说明#

参数类型说明
basestruct event_base*要退出的事件基
tvconst struct timeval*退出延迟时间,NULL表示立即退出

返回值#

  • 成功:返回 0
  • 失败:返回 -1

2.7 event_base_loopbreak API 详解#

int event_base_loopbreak(struct event_base *base);

参数说明#

参数类型说明
basestruct event_base*要中断的事件基

返回值#

  • 成功:返回 0
  • 失败:返回 -1

2.8 event_base_free API 详解#

void event_base_free(struct event_base *base);

参数说明#

参数类型说明
basestruct event_base*要释放的事件基

2.9 基本操作示例#

// 创建事件基
struct event_base *base = event_base_new();
if (!base) {
fprintf(stderr, "Failed to create event base\n");
return 1;
}
// 带配置创建事件基
struct event_config *cfg = event_config_new();
event_config_require_features(cfg, EV_FEATURE_ET);
struct event_base *base_with_config = event_base_new_with_config(cfg);
event_config_free(cfg);
// 启动事件循环(阻塞模式)
event_base_dispatch(base);
// 启动事件循环(非阻塞模式)
event_base_loop(base, EVLOOP_NONBLOCK);
// 延迟退出事件循环
struct timeval tv = {5, 0}; // 5秒后退出
event_base_loopexit(base, &tv);
// 立即中断事件循环
event_base_loopbreak(base);
// 释放事件基
event_base_free(base);
event_base_free(base_with_config);

三、事件(Event)#

在 libevent 中,事件(Event)代表了一个具体的事件源及其相关的事件处理器。事件可以绑定到不同的事件源上,如文件描述符、网络套接字等。

3.1 event_new API 详解#

struct event *event_new(struct event_base *base, evutil_socket_t fd, short flags,
event_callback_fn callback, void *arg);

参数说明#

参数类型说明
basestruct event_base*事件所属的事件基
fdevutil_socket_t事件绑定的文件描述符,对于定时器事件设为-1
flagsshort事件标志,如 EV_READ、EV_WRITE、EV_PERSIST 等
callbackevent_callback_fn事件触发时的回调函数
argvoid*传递给回调函数的参数

返回值#

  • 成功:返回事件结构体指针
  • 失败:返回 NULL

回调函数签名#

typedef void (*event_callback_fn)(evutil_socket_t fd, short events, void *arg);
参数类型说明
fdevutil_socket_t事件绑定的文件描述符
eventsshort触发的事件类型,如 EV_READ、EV_WRITE 等
argvoid*传递给回调函数的参数

3.2 event_add API 详解#

int event_add(struct event *ev, const struct timeval *timeout);

参数说明#

参数类型说明
evstruct event*要添加的事件
timeoutconst struct timeval*超时时间,NULL表示无超时

返回值#

  • 成功:返回 0
  • 失败:返回 -1

3.3 event_del API 详解#

int event_del(struct event *ev);

参数说明#

参数类型说明
evstruct event*要删除的事件

返回值#

  • 成功:返回 0
  • 失败:返回 -1

3.4 event_free API 详解#

void event_free(struct event *ev);

参数说明#

参数类型说明
evstruct event*要释放的事件

3.5 事件的主要属性#

属性说明
描述符(Descriptor)事件绑定的文件描述符或套接字
标志(Flags)表示事件类型和行为的标志位,如 EV_READ、EV_WRITE、EV_PERSIST 等
回调函数(Callback)事件发生时调用的函数
回调参数(Argument)传递给回调函数的参数

3.6 事件操作示例#

// 创建事件
struct event *ev = event_new(base, fd, EV_READ | EV_PERSIST, read_callback, arg);
if (!ev) {
fprintf(stderr, "Failed to create event\n");
return -1;
}
// 添加事件(无超时)
if (event_add(ev, NULL) < 0) {
fprintf(stderr, "Failed to add event\n");
event_free(ev);
return -1;
}
// 添加事件(带超时)
struct timeval tv = {5, 0}; // 5秒超时
if (event_add(ev, &tv) < 0) {
fprintf(stderr, "Failed to add event with timeout\n");
event_free(ev);
return -1;
}
// 删除事件
if (event_del(ev) < 0) {
fprintf(stderr, "Failed to delete event\n");
}
// 释放事件
event_free(ev);

四、事件处理(Event Handling)#

事件处理是 libevent 的核心功能之一。当事件发生时,事件基会调度相应的事件处理器。

void event_callback(evutil_socket_t fd, short event, void *arg) {
// 处理事件
}
struct event *event = event_new(base, fd, EV_READ | EV_PERSIST, event_callback, arg);
event_add(event, NULL); // 添加事件

五、事件标志#

事件标志用于指定事件的类型和行为:

标志值说明
EV_TIMEOUT0x01定时事件
EV_READ0x02读事件,表示当文件描述符可读时触发事件
EV_WRITE0x04写事件,表示当文件描述符可写时触发事件
EV_SIGNAL0x08信号事件
EV_PERSIST0x10持久事件,表示事件在触发后不会自动删除,而是继续保留在事件基中
EV_ET0x20边缘触发模式,仅在数据可用时触发

六、定时器(Timer)#

libevent 支持定时器功能,允许开发者在特定的时间间隔内执行任务。

void timer_callback(evutil_socket_t fd, short event, void *arg) {
printf("Timer fired!\n");
}
// -1 表示定时器不绑定到任何文件描述符
struct event *timer = event_new(base, -1, EV_PERSIST, timer_callback, NULL);
struct timeval delay = {5, 0}; // 设置定时器时间为 5 秒
event_add(timer, &delay);

七、信号处理#

libevent 支持信号处理,允许开发者在接收到特定信号时执行相应的动作。

void signal_handler(evutil_socket_t fd, short event, void *arg) {
printf("Signal received!\n");
event_base_loopexit(base, NULL);
}
struct event *signal_event = evsignal_new(base, SIGINT, signal_handler, base);
event_add(signal_event, NULL);

八、多线程支持#

libevent 支持多线程环境,允许开发者在多线程程序中安全地使用事件基。

event_base_mutex_lock(base);
event_base_mutex_unlock(base);

九、事件基的生命周期#

事件基的生命周期包括创建、启动和销毁三个阶段:

  1. 创建:使用 event_base_new() 创建事件基
  2. 启动:使用 event_base_dispatch() 启动事件循环
  3. 销毁:使用 event_base_free() 销毁事件基

十、示例代码#

下面是一个完整的示例代码,展示了如何使用 libevent 创建一个简单的定时器:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <event2/event.h>
static void timer_callback(evutil_socket_t fd, short event, void *arg) {
printf("Timer fired!\n");
// 重新调度定时器
struct event *timer = (struct event *)arg;
struct timeval delay = {5, 0};
event_add(timer, &delay);
}
int main() {
struct event_base *base;
struct event *timer;
base = event_base_new();
if (!base) {
fprintf(stderr, "Failed to create event base\n");
return 1;
}
timer = event_new(base, -1, EV_PERSIST, timer_callback, timer);
if (!timer) {
fprintf(stderr, "Failed to create timer event\n");
event_base_free(base);
return 1;
}
struct timeval delay = {5, 0};
event_add(timer, &delay);
event_base_dispatch(base);
event_free(timer);
event_base_free(base);
return 0;
}

十一、使用注意事项#

11.1 事件基的管理和使用#

  • 单线程原则:事件基(event_base)的设计是单线程的,即一个事件基只能在一个线程中使用。如果在多线程环境下使用 libevent,每个线程应有自己的事件基实例。
struct event_base *base1 = event_base_new(); // 第一个线程的事件基
struct event_base *base2 = event_base_new(); // 第二个线程的事件基
  • 线程安全:虽然 libevent 提供了一些线程安全的功能,但在多线程环境中,对事件基的操作(如添加、删除事件)必须确保线程安全。

11.2 回调函数的设计#

  • 非阻塞性:事件处理函数(回调函数)不应执行长时间的阻塞操作,否则会影响事件循环的效率。
  • 资源管理:在事件处理函数中,应妥善管理资源,确保资源的正确释放。

11.3 定时器的使用#

  • 精确度:定时器的精度取决于底层操作系统提供的定时器机制。在某些情况下,定时器的触发时间可能会有所偏差。
  • 循环定时器:使用 EV_PERSIST 标志创建的定时器会在每次触发后自动重新调度。

其他相关资料 请移步到个人主页

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
🔑 核心概念与API - libevent源码深度解析系列(四)
https://xutopia.top/blog/libevent-core-concepts/
作者
xutopia77
发布于
2026-04-11
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
xutopia77
以 C/C++ 为根基做系统与音视频,用全栈能力把想法落地,同时把思考写成文字。
分类
标签
站点统计
文章
48
分类
12
标签
22
总字数
95,084
运行时长
0 天
最后活动
0 天前
文章目录