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

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

Toolbar+DrawerLayout使用详情结合网络各大神

最近也想搞下toolbar+drawerlayout的使用。结合网络上各大神的杰作,我把大部分的内容效果都完成了遍。现在记录下各个功能效果的实现以及一些细节注意点。 这图弹出两个菜单内容都是仿QQ界面的选项。左边一个是drawerlayout的弹窗。右边是toolbar的popup弹窗。 开始实现步骤详情: 1.创建toolbar布局跟drawerlayout布局 <?xml vers

C#中,decimal类型使用

在Microsoft SQL Server中numeric类型,在C#中使用的时候,需要用decimal类型与其对应,不能使用int等类型。 SQL:numeric C#:decimal

探索Elastic Search:强大的开源搜索引擎,详解及使用

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引入 全文搜索属于最常见的需求,开源的 Elasticsearch (以下简称 Elastic)是目前全文搜索引擎的首选,相信大家多多少少的都听说过它。它可以快速地储存、搜索和分析海量数据。就连维基百科、Stack Overflow、

flask 中使用 装饰器

因为要完成毕业设计,我用到fountain code做数据恢复。 于是在github上下载了fountain code的python原代码。 github上的作者用flask做了fountain code的demo。 flask是面向python的一个网站框架。 里面有用到装饰器。 今天笔试的时候,我也被问到了python的装饰器。

mathematica的使用

因为做实验用到Bloom filter这一技术,Bloom filter里面的数学公式可以用来画图。 那么用什么画图软件比较好呢? 当然是Mathematica啦。 利用代码Plot[{y=x},{x,0,100}] 就可以画出比较好的图 简直nice