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

相关文章

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Python文件操作与IO流的使用方式

《Python文件操作与IO流的使用方式》:本文主要介绍Python文件操作与IO流的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、python文件操作基础1. 打开文件2. 关闭文件二、文件读写操作1.www.chinasem.cn 读取文件2. 写

PyQt6中QMainWindow组件的使用详解

《PyQt6中QMainWindow组件的使用详解》QMainWindow是PyQt6中用于构建桌面应用程序的基础组件,本文主要介绍了PyQt6中QMainWindow组件的使用,具有一定的参考价值,... 目录1. QMainWindow 组php件概述2. 使用 QMainWindow3. QMainW

使用Python自动化生成PPT并结合LLM生成内容的代码解析

《使用Python自动化生成PPT并结合LLM生成内容的代码解析》PowerPoint是常用的文档工具,但手动设计和排版耗时耗力,本文将展示如何通过Python自动化提取PPT样式并生成新PPT,同时... 目录核心代码解析1. 提取 PPT 样式到 jsON关键步骤:代码片段:2. 应用 JSON 样式到

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

关于Mybatis和JDBC的使用及区别

《关于Mybatis和JDBC的使用及区别》:本文主要介绍关于Mybatis和JDBC的使用及区别,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、JDBC1.1、流程1.2、优缺点2、MyBATis2.1、执行流程2.2、使用2.3、实现方式1、XML配置文件

macOS Sequoia 15.5 发布: 改进邮件和屏幕使用时间功能

《macOSSequoia15.5发布:改进邮件和屏幕使用时间功能》经过常规Beta测试后,新的macOSSequoia15.5现已公开发布,但重要的新功能将被保留到WWDC和... MACOS Sequoia 15.5 正式发布!本次更新为 Mac 用户带来了一系列功能强化、错误修复和安全性提升,进一步增

Java资源管理和引用体系的使用详解

《Java资源管理和引用体系的使用详解》:本文主要介绍Java资源管理和引用体系的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Java的引用体系1、强引用 (Strong Reference)2、软引用 (Soft Reference)3、弱引用 (W

ubuntu系统使用官方操作命令升级Dify指南

《ubuntu系统使用官方操作命令升级Dify指南》Dify支持自动化执行、日志记录和结果管理,适用于数据处理、模型训练和部署等场景,今天我们就来看看ubuntu系统中使用官方操作命令升级Dify的方... Dify 是一个基于 docker 的工作流管理工具,旨在简化机器学习和数据科学领域的多步骤工作流。