libevent使用(二) ----- event_base 和 event

2024-06-22 19:58
文章标签 使用 libevent base event

本文主要是介绍libevent使用(二) ----- event_base 和 event,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于event_base

如果设置event_base使用锁,则可以安全的在多线程这使用它。

然而,其 事件循环则只能运行在一个线程中,如果需要用多个线程检测IO,则需要为每个线程使用一个event_base。


建立默认的event_base
struct event_base *event_base_new(void)
//函数分配并返回一个新的具有默认设置的event_base。函数会检测环境变量,返回一个到event_base的指针
//发生错误则返回NULL。
//选择I/O复用方法时,也会选择系统支持的最快的方法。


检查event_base的后端方法
有时我们可能需要检查event_base支持哪些特性,以及使用的哪种IO复用
const char **event_get_support_methods(void)
//此函数返回一个数组的指针,数组内容是当前版本libevent支持的I/O复用方法的名字
//数组最后一个元素是NULL

const char *event_base_get_method(const struct event_base *)
//此函数返回event_base真正使用的IO复用方法
enum event_method_feature event_base_get_features(const struct event_base *)
//此函数则返回支持的特征掩码, 可通过与某特征相与判断是否支持该特征



释放申请的event_base
void event_base_free(struct event_base*)
//要注意的是这个函数只是释放event_base, 不释放相关的event等


设置event_base的 优先级
int event_base_priority_init(struct event_base *, int n_priorities)
//event_base默认只支持单个优先级, 而支持为事件设置多个优先级,即调用此函数设置优先级数目
//此函数修改的是支持的优先级数目。每个新的事件的可用优先级从0(最高)到 n_priorities-1(最低)
//要注意的是。要在任何事件激活之前调用此函数
//新事件的优先级被初始化为 n_priorities/2



在fork之后重新初始化
event_base
int event_reinit(struct event_base *)
Example:

struct event_base *base = event_base_new();/* ... add some events to the event_base ... */if (fork()) {/* In parent */continue_running_parent(base); /*...*/
} else {/* In child */event_reinit(base);continue_running_child(base); /*...*/
}


当我们拥有了一个event_base,和几个注册了的event之后,我们希望开始执行循环,等待事件、发出提醒。

int event_base_loop(struct event_base *base, int flags)
//#define EVLOOP_ONCE             0x01
// 函数会等待某些事件成为"active", 运行他们直到没有事件可运行,然后调用return
//#define EVLOOP_NONBLOCK         0x02
// 函数不会等待事件成为"active", 只是检查是否有事件已准备好,没有就返回,有就执行回调函数
//#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
// 默认情况下,只要有已注册事件存在,函数就一直运行event_base,直到没有任何注册事件了就退出。我们也可以修改这种默认行为,也就是使用这个标识。使用此标识后,循环会继续,直到某线程调用 event_base_loopbreak或是 event_base_exit 。继续执行期间也可通过其他线程给此base添加事件。
//执行循环时,函数重复检查是否有任何已注册事件被激活了(读就绪?超时?)。如果有事件被触发,函数就标记事件为"active"的,并且开始处理他们


方便理解:
while (any events are registered with the loop,or EVLOOP_NO_EXIT_ON_EMPTY was set) {if (EVLOOP_NONBLOCK was set, or any events are already active)If any registered events have triggered, mark them active.elseWait until at least one event has triggered, and mark it active.for (p = 0; p < n_priorities; ++p) {if (any event with priority of p is active) {Run all active events with priority of p.break; /* Do not run any events of a less important priority */}}if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)break;
}


函数 event_base_dispatch(struct base *) 与 event_base_loop(...)的默认方式类似


停止循环
int event_base_loopexit(struct event_base *base, struct timeval *tv)
//即使有注册时间也退出。如果tv为空,立刻执行。然而如果正在为"active"的句柄调用回调函数,那么会执行完所有"active"的回调函数才结束 
int event_base_loopbreak(struct event_base *)
//如果有正在执行的句柄回调函数,那么执行完这个句柄函数后就结束,而不是像event_base_loopexit函数一样会把所有回调函数执行完

还要注意的是event_base_loopexit(base,NULL)和event_base_loopbreak(base)在事件循环没有运行时的行为不同:
前者安排下一次事件循环在下一轮回调完成后立即停止; 后者仅仅停止当前正在运行的循环








关于event

构建事件对象

#define EV_TIMEOUT      0x01(这个标识在event_new里面是被忽略的,可以在 event_add 的时候设置)
#define EV_READ         0x02
#define EV_WRITE        0x04
#define EV_SIGNAL       0x08
#define EV_PERSIST      0x10
#define EV_ET           0x20typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);
void event_free(struct event *event);



关于 事件的持久性(即 EV_PERSIST
默认情况下,每当未决事件成为激活的,事件将在其回调函数被执行前成为非未决的。如果想让事件再次成为为未决的,可以在回调函数中再次对其调用event_add
然而如果设置了此标识,事件就是持久的 。这意味着即使其回调被激活,事件还是保持为未决的状态。如果想在回调中让事件成为非未决的,可以对其调用 event_del()
因此,每次执行事件回调的时候,持久事件的超时值会被复位。
如果具有 EV_READ | EV_PERSISIT标识,且超时为5秒,事件将在以下情况成为active的:
1、可读
2、从最后一次激活开始,过去了5秒



要注意的是,每个进程任何时刻只能有一个event_base可以监听信号,如果同时向两个event_base添加信号事件,即使是不同的信号,只有一个base会收到信号


让事件未决和非未决
int event_add(struct event *ev, const struct timeval *tv);
int event_del(struct event *ev);
//要注意的是,如果你在某事件成为"active"且在调用回调函数之前使用event_del移除该事件,那么回调函数是不会被执行的


移除事件定时器
int event_remove_timer(struct event *ev);
//使用此函数可以在不移除事件的情况下一处超时时间
//如果是单纯的超时时间,那么相当于event_del函数



事件的优先级

当许多事件同时发生时,回调函数的执行顺序是未定义的,可以通过priority来指定某些事件比某些事件重要
int event_priority_set(struct event *, int priority);
//此优先级最大值为设置的event_base的优先级减去1



检查事件的状态
有时候我们可能需要判断一个事件是否已经添加进base,或想知道事件代表什么


int event_pending(const struct event *ev, short what, struct timeval *tv_out);
//The event_pending function determines whether the given event is pending or active. If it is, and any of the flags EV_READ, EV_WRITE, EV_SIGNAL, and EV_TIMEOUT are set in the what argument, the function returns all of the flags that the event is currently pending or active on. If tv_out is provided, and EV_TIMEOUT is set in what, and the event is currently pending or active on a timeout, then tv_out is set to hold the time when the event’s timeout will expire.#define event_get_signal(ev) /* ... */
evutil_socket_t event_get_fd(const struct event *ev);
struct event_base *event_get_base(const struct event *ev);
short event_get_events(const struct event *ev);
event_callback_fn event_get_callback(const struct event *ev);
void *event_get_callback_arg(const struct event *ev);
int event_get_priority(const struct event *ev);

void event_get_assignment(const struct event *event,struct event_base **base_out,evutil_socket_t *fd_out,short *events_out,event_callback_fn *callback_out,void **arg_out);
//The event_get_assignment() function copies all of the assigned fields of the event into the provided pointers. If any of the pointers is NULL, it is ignored.




给出使用实例:


#include <event2/event.h>
#include <stdio.h>/* Change the callback and callback_arg of 'ev', which must not be* pending. */
int replace_callback(struct event *ev, event_callback_fn new_callback,void *new_callback_arg)
{struct event_base *base;evutil_socket_t fd;short events;int pending;//函数返回事件是否是未决的pending = event_pending(ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT,NULL);
//如果是未决的,那我们此时不要操作(未决即当前事件挂在base上等待事件发生)if (pending) {/* We want to catch this here so that we do not re-assign a* pending event.  That would be very very bad. */fprintf(stderr,"Error! replace_callback called on a pending event!\n");return -1;}//非未决,那么复制所有为事件分配的字段到提供的指针中event_get_assignment(ev, &base, &fd, &events,NULL /* ignore old callback */ ,NULL /* ignore old callback argument */);//重新为此事件指定回调函数和参数event_assign(ev, base, fd, events, new_callback, new_callback_arg);return 0;
}



配置 一次性触发事件
int event_base_once(struct event_base *, evutil_socket_t, short,void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
//此函数类似 event_new, 但是会在回调函数后内部释放event结构
//不能删除或者手动激活使用此函数插入的事件。如果希望能取消事件,那么使用 event_new 或 event_assign


手动激活事件
void event_active(struct event *ev, int what, short ncalls);
//此函数使事件被激活,且带有标识what
//事件不需要是未决的,激活事件也不会让他成为未决的

这篇关于libevent使用(二) ----- event_base 和 event的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085268

相关文章

postgresql使用UUID函数的方法

《postgresql使用UUID函数的方法》本文给大家介绍postgresql使用UUID函数的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录PostgreSQL有两种生成uuid的方法。可以先通过sql查看是否已安装扩展函数,和可以安装的扩展函数

如何使用Lombok进行spring 注入

《如何使用Lombok进行spring注入》本文介绍如何用Lombok简化Spring注入,推荐优先使用setter注入,通过注解自动生成getter/setter及构造器,减少冗余代码,提升开发效... Lombok为了开发环境简化代码,好处不用多说。spring 注入方式为2种,构造器注入和setter

MySQL中比较运算符的具体使用

《MySQL中比较运算符的具体使用》本文介绍了SQL中常用的符号类型和非符号类型运算符,符号类型运算符包括等于(=)、安全等于(=)、不等于(/!=)、大小比较(,=,,=)等,感兴趣的可以了解一下... 目录符号类型运算符1. 等于运算符=2. 安全等于运算符<=>3. 不等于运算符<>或!=4. 小于运

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

Python 字典 (Dictionary)使用详解

《Python字典(Dictionary)使用详解》字典是python中最重要,最常用的数据结构之一,它提供了高效的键值对存储和查找能力,:本文主要介绍Python字典(Dictionary)... 目录字典1.基本特性2.创建字典3.访问元素4.修改字典5.删除元素6.字典遍历7.字典的高级特性默认字典

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定