电子说
REventBus背景
在实际的项目开发中,经常会遇到业务与业务,组件与组件,业务与组件之间的通信,举个例子:当有烟雾传感器检测到烟雾超标时,需要打开排气扇排气,同时显示烟雾浓度显示到显示器中,供管理人员检视。处理这样的逻辑有几种策略。如下:
排气扇任务和显示器任务,不断的查询烟雾浓度,各自处理检测烟雾浓度是否超标。
烟雾模块提供注册监听接口,排气扇任务和显示器任务分别注册监听,当浓度超标时,告知监听任务。
以上两种策略都存在很大的问题,问题分析:
第一种策略,每一个任务都需要不断检查判断,这会导致资源的浪费,而且代码也会有很多重复的。
第二种策略,虽然解决了第一种策略的的问题,但是如果场景中存在不止一个传感器时,那么所需要注册的监听接口将随之增加。而且监听接口是跟具体的业务绑定的。
综上所述:为了能够解决上面的问题,REventBus组件应运而生。开源链接:https://gitee.com/RiceChen0/revent_bus
REventBus工作流程图解
Publisher使用publish发出ige一个事件,Subscriber在其回调函数中接收事件。
REventBus依赖组件
为了提供更好的组件化,风火轮科技 和《Rice嵌入式开发技术分享》公众号联合推出R组件集,REventbus组件就是R组件集的其中一员,组件与组件之后存在依赖关系.REventBus组件同样依赖一些组件,如下:
RPlatform组件:平台适配层,为了能让R组件能够在不同RTOS或Linux中运行,针对不同平台做的适配层。链接:https://gitee.com/RiceChen0/rplatform。
RThread_pool组件:一个跨平台,易移植,接口简单的线程池组件。链接:https://gitee.com/RiceChen0/rthread_pool。
REventBus的使用
REventBus整体包含5部分:Subscribe,Publish,Event,EventCb,Broker。
Subscribe --订阅者订阅自己需要监听的事件接口。
Publish --发布者发布事件,它支持同步发送和异步发送。
Event --订阅者监听的事件,只有存在订阅事件,才会有与之对应的发布事件。
EventCb --事件产生的回调接口,订阅者注册,发布者发布对应事件之后产生回调。
Broker --事件代理,管理事件注册,注销,监听。
REventBus接口说明
接口 | 说明 |
---|---|
reb_init | REventBus初始化接口 |
reb_deinit | REventBus去初始化接口 |
reb_subscribe | REventBus订阅事件接口 |
reb_unsbscribe | REventBus取消订阅事件接口 |
reb_publish | REventBus同步发布事件接口 |
reb_async_publish | REventBus异步发布事件接口 |
REventBus初始化接口
使用RThread_pool组件创建一个线程池
创建互斥量,解决共享资源问题。
初始化broker链表,用于事件代理。
pf_err_t reb_init(void);
REventBus去初始化接口
线程池注销,互斥量伤处,
pf_err_t reb_deinit(void);
REventBus订阅事件接口: pf_err_t reb_subscribe(const char *event, reb_handler_cb handler)
参数 | 描述 |
---|---|
event | 订阅的事件,其是一个字符串类型 |
handler | 事件处理函数,由订阅者提供,事件产生时回调此函数 |
返回 | —— |
PF_EOK | 订阅事件成功 |
OTher | 订阅事件失败 |
REventBus订阅事件接口: pf_err_t reb_unsbscribe(const char *event, reb_handler_cb handler)
参数 | 描述 |
---|---|
event | 订阅的事件,其是一个字符串类型 |
handler | 事件处理函数,订阅事件时所订阅的回调函数 |
返回 | —— |
PF_EOK | 取消订阅事件成功 |
OTher | 取消订阅事件失败 |
REventBus同步发布事件接口:pf_err_t reb_publish(const char *event, void *payload, uint16_t lenght)
参数 | 描述 |
---|---|
event | 订阅者订阅的事件类型 |
payload | 发布事件的消息类型 |
lenght | 发布事件的消息长度 |
返回 | —— |
PF_EOK | 发布事件成功 |
OTher | 发布事件失败 |
REventBus异步发布事件接口:pf_err_t reb_async_publish(const char *event, reb_priority priority, void *payload, uint16_t lenght)
参数 | 描述 |
---|---|
event | 订阅者订阅的事件类型 |
priority | 发布事件的优先级,REB_PRIORITY_HIGH和REB_PRIORITY_ORDINARY(目前未实现) |
payload | 发布事件的消息类型 |
lenght | 发布事件的消息长度 |
返回 | —— |
PF_EOK | 发布事件成功 |
OTher | 发布事件失败 |
REventBus演示
订阅事件demo:
注意:同一个模块定义多次定义同一个事件,只有第一个事件订阅有效
#include#include #include #include "revent_bus.h" void reb_handler(const char *event, void *payload, uint16_t lenght) { rt_kprintf("Recv: event: %s, payload: %.*s ", event, lenght, payload); } int main(void) { reb_init(); reb_subscribe("event1", reb_handler); reb_subscribe("event1", reb_handler); reb_subscribe("event2", reb_handler); reb_info_dump(); }
效果:
发布同步事件demo:
注意:发布同步事件,它是按照顺序发布的,只有第一个事件处理完,才会处理第二个事件。
#include#include #include #include "revent_bus.h" void reb_handler(const char *event, void *payload, uint16_t lenght) { rt_kprintf("Recv: event: %s, payload: %.*s ", event, lenght, payload); } int main(void) { rt_kprintf("---------------------- "); rt_kprintf("-Webcome to youyeetoo- "); rt_kprintf("---------------------- "); reb_init(); reb_subscribe("event1", reb_handler); reb_subscribe("event1", reb_handler); reb_subscribe("event2", reb_handler); reb_info_dump(); while (1) { reb_publish("event1", "youyeetoo: event bus", rt_strlen("youyeetoo: event bus")); reb_publish("event2", "Publish sync msg", rt_strlen("Publish sync msg")); rt_thread_delay(1000); } }
效果:
发布异步事件demo:
注意:发布异步事件,发布的事件不一定立马执行,他会等待线程池的任务空闲时,才会执行。也就是执行时间不确定。
#include#include #include #include "revent_bus.h" void reb_handler(const char *event, void *payload, uint16_t lenght) { rt_kprintf("Recv: event: %s, payload: %.*s ", event, lenght, payload); } int main(void) { rt_kprintf("---------------------- "); rt_kprintf("-Webcome to youyeetoo- "); rt_kprintf("---------------------- "); reb_init(); reb_subscribe("event1", reb_handler); reb_subscribe("event1", reb_handler); reb_subscribe("event2", reb_handler); reb_info_dump(); while (1) { reb_publish("event1", "youyeetoo: event bus", rt_strlen("youyeetoo: event bus")); reb_publish("event2", "Publish sync msg", rt_strlen("Publish sync msg")); rt_thread_delay(100); reb_async_publish("event1", REB_PRIORITY_ORDINARY, "Good Good", rt_strlen("Good Good")); reb_async_publish("event2", REB_PRIORITY_ORDINARY, "Publish async msg", rt_strlen("Publish async msg")); rt_thread_delay(100); } }
效果:
REventBus的优缺点
优点:
简化组件与组件,业务与业务,组件与业务之间的通信方式。
对通信双方做到完全解耦。
使用RThread pool灵活切换工作线程,一定程度提供了事件处理效率
支持同步事件发布,和异步事件发布。
资源占用极小。
缺点:
当业务多的时候,需要定义很多事件类型。
订阅事件的时候,需要遍历事件列表是否已经存在事件;发布的时候,也需要遍历事件列表是否已经存在事件,性能不高。
全部0条评论
快来发表一下你的评论吧 !