MT7688学习笔记(8)——使用libevent创建定时器

一、简介

libevent 默认情况下是单线程的,可以配置成多线程,每个线程有且只有一个event_base,对应一个struct event_base结构体以及附于其上的事件管理器,用来调度托管给它的一系列event,可以和操作系统的进程管理类比。当一个事件发生后,event_base会在合适的时间,不一定是立即去调用绑定在这个事件上的函数,直到这个函数执行完,再去调度其他的事件。

event_base内部有一个循环,循环阻塞在epoll等系统调用上,直到有一个/一些时间发生,然后去处理这些事件。当然,这些事件要被绑定在这个event_base上,每个事件对应一个struct event,可以是监听一个fd或者信号量之类的,struct event使用event_new来创建和绑定,使用event_add来将event绑定到event_base中。

libevent 中,用 最小堆(min-heap) 来管理所有定时器。
root node 就是最近即将触发的 timer event。node value 就是 timer 触发的时间(秒)。

二、流程

1、初始化libevent
2、设置事件
3、添加事件
4、进入循环

2.1 初始化libevent

首先初始化libevent库,并保存返回的指针
struct event_base *base = event_base_new();
这一步相当于初始化一个Reactor实例;在初始化libevent后,就可以注册事件了。

2.2 设置事件

2.2.1 定义两个结构体

分别代表事件和定时器值
struct event ev; //定时器事件
struct timeval timeout; //定时器值

2.2.2 将事件和event_base绑定

event_assgin()函数
原型:
int event_assign(struct event *event, struct event_base *base, evutil_socket_t fd, short what, void (*callback)(evutil_socket_t, short, void *), void *arg);
用法:
event_assign(&ev, base, -1, flags, cb_func, (void*)&ev);

在创建定时器事件时,使用的是struct event ev,也可以用event_new函数动态分配,这样就不需要event_assign函数了。

event_new()函数
原型:
struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);
用法:
struct event *ev = event_new(base, -1, what, cb_func, arg);

其中,what事件类型及属性如下:
#define EV_TIMEOUT 0x01 // 定时事件
#define EV_READ 0x02 // I/O事件
#define EV_WRITE 0x04 // I/O事件
#define EV_SIGNAL 0x08 // 信号
#define EV_PERSIST 0x10 // 永久事件
#define EV_ET 0x20 // 边沿触发

回调函数
void cb_func(evutil_socket_t fd, short what, void *arg);
在分配后可以用event_free来释放
event_free(ev);

2.3 添加事件

虽然已经初始化了事件,但是该事件并不会被触发,原因在于我们并没有激活该事件。
event_add()函数提供了激活事件的功能。
event_add()函数
原型:
int event_add(struct event *ev, const struct timeval *tv);
用法:
event_add(ev, &timeout)
如果是一个(non-pending)未注册ev,调用event_add函数会注册该事件(变为pending状态)。如果是一个(pending)注册过的ev,调用该函数会在tv时间后重新注册该事件。成功返回0,失败返回-1。

2.4 进入循环

程序进入无限循环,等待就绪事件并执行事件处理
event_base_dispatch()函数
原型:
int event_base_dispatch(struct event_base *base);
用法:
event_base_dispatch(base);
还可以使用event_base_loop()函数。

三、头文件

#include <event2/event.h>

四、例子

void mian(void)
{
    struct event_base *base = event_base_new();

    CreateTimer(base, 2, 0, true, DoCallBack, nullptr);     
            
    event_base_dispatch(base);
    event_base_free(base);
}

/**
 @brief 创建定时器
 @param base 指向event_base类型的指针
 @param sec 秒数
 @param usec 微秒数
 @param repeat 是否重复
 @param func() 回调函数
 @param arg 指向传递给这个回调函数来使用的参数
 @return true - 成功;false - 失败
*/
bool CreateTimer(event_base *base,int sec,int usec,bool repeat,void (*func)(evutil_socket_t ,short ,void *),void *arg)
{
    if (base == nullptr)
    {
        return false;
    }
    if ((sec == 0) && (usec == 0))
    {
        return false;
    }
    
    struct timeval timeout;
    
    /* 初始化事件
    * base:event_base类型,event_base_new的返回值
    * fd:监听的fd,listen的fd。 定时事件fd为 -1
    * what:事件的类型及属性 EV_PERSIST - 永久事件,使得event_add永久生效,直到event_del调用
    * cb:绑定的回调函数
    * arg:给回调函数的参数
    */
    struct event *ev = event_new(base, -1, repeat?EV_PERSIST:0, func, arg);
    
    if (ev)
    {
        timeout.tv_sec = sec;       // 秒
        timeout.tv_usec = usec;     // 微秒
        /* 激活事件
        * 如果是一个未注册'ev',调用'event_add'函数会注册该事件
        * 如果是一个注册过的'ev',调用该函数会在tv时间后重新注册该事件
        */
        event_add(ev, &timeout);
        return true;
    }   
    return false;
}

• 由 Leung 写于 2018 年 11 月 2 日

• 参考:Libevent学习——定时器基本运用
    事件注册与循环监听
    libevent学习篇之一:libevent快速入门
    libevent timer 的原理 (min-heap)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容