精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

超精簡的訂閱發布事件組件--SPEvent

Rice嵌入式開發技術分享 ? 來源: Rice 嵌入式開發技術分 ? 作者: Rice 嵌入式開發 ? 2023-01-22 13:45 ? 次閱讀

概述

  • 本文主要描述一個超精簡的訂閱發布事件組件--SPEvent。
  • 在實際開發過程中,一個事件的產生會產生很多業務的執行,或者多個事件都要執行同一個業務的執行。在這種場景下有兩種做法:
  1. 將同一個事件的業務放在一個函數中,然后事件產生的時候執行對應的函數。
  2. 某個業務需要哪個事件,它自己監聽對應事件并執行。
  • 顯然,第一種策略會將業務與業務之間耦合在一起,對后期維護是非常痛苦的;第二種顯然會更加有優勢,不同業務完全解耦,獨立完成事件的業務。
  • 第二種策略的方式,實際在軟件架構中經常看到,比如MQTT的通信(通過訂閱對應的topic去監聽對應內容)。
  • 有了上述的需求,作者做了一個超精簡的訂閱發布事件組件。整個邏輯很簡單。

超精簡的SPEvent組件,實現方法

  1. 整個訂閱發布事件機制,引入兩個東西:EventHub和EventNode。

  • EventHub:每一個事件類型都為一個EventHub,然后掛在HubList中。
  • EventNode:每一個訂閱事件的業務為一個EventNode,然后掛在對應的EventHub中。
  • 整個訂閱發布事件機制圍繞著EventHub和EventNode,特點:

  • 資源占用極小,接口操作簡單
  • 事件支持動態訂閱,動態注銷。
  • SPEvent采用雙向鏈表進行維護整個訂閱-發布邏輯

  • SPEvent一定存在一個EventHubList鏈表來維護事件類型,它默認是沒有任何EventHub節點,
  • 訂閱事件流程:當訂閱者訂閱事件之后,如果事件不存在,則申請一個EventHub,并將EventHub掛在到EventHubList鏈表中;然后申請一個EventNode,及將對應EventNode掛在EventNodeList鏈表。
  • 發布事件流程:當發布者發布事件時,會從EventHubList中查詢有沒有對應的EventHub,如果EventHub存在,則將事件消息發布給對應EventHub下所有EventNode。
  • 注銷事件訂閱流程:當訂閱者注銷已經訂閱的事件,會從EventHubList中查詢有沒有對應的EventHub,如果EventHub存在,則將對應EventNode從EventHub中刪除。

9e3996c2-9815-11ed-92c9-dac502259ad0.png

超精簡的SPEvent組件,接口說明:

函數 說明
SPEventInit 初始化函數
SPEventDeinit 去初始化函數
SPEventSubscribe 訂閱事件函數
SPEventUnsubscribe 注銷訂閱事件函數
SPEventPublish 發布事件消息
SPEventClear 清除事件池
RecvtInfoDump 導出事件池信息

超精簡的SPEvent組件,代碼實現

  1. 整個代碼接口存在3個文件:spevent.c、spevent.h、spevent_def.h。其中:
  2. spevent_def.h文件說明:定義了屏蔽平臺相關接口的宏和定義了雙向量表操作的宏定義。雙向量表在SPEvent中式至關重要數據結構:
#ifndef__SPEVENT_DEF_H__
#define__SPEVENT_DEF_H__



#include
#include
#include
#include
#include
#include
#include

#defineSPEVENT_INLINEstatic__inline
#defineSPEVENT_EVENT_NAME_LEN16

#ifndefSPEVENT_MALLOC
#defineSPEVENT_MALLOCmalloc
#endif

#ifndefSPEVENT_FREE
#defineSPEVENT_FREEfree
#endif

#ifndefSPEVENT_PRINT
#defineSPEVENT_PRINTprintf
#endif

structSPEventListNode
{
structSPEventListNode*next;
structSPEventListNode*prev;
};
typedefstructSPEventListNodeSPEventList;

SPEVENT_INLINEvoidSPEVENT_LIST_INIT(SPEventList*l)
{
l->next=l->prev=l;
}

SPEVENT_INLINEvoidSPEVENT_LIST_INSERT_AFTER(SPEventList*l,SPEventList*n)
{
l->next->prev=n;
n->next=l->next;
l->next=n;
n->prev=l;
}

SPEVENT_INLINEvoidSPEVENT_LIST_INSERT_BEFORE(SPEventList*l,SPEventList*n)
{
l->prev->next=n;
n->prev=l->prev;
l->prev=n;
n->next=l;
}

SPEVENT_INLINEvoidSPEVENT_LIST_REMOVE(SPEventList*n)
{
n->next->prev=n->prev;
n->prev->next=n->next;
n->next=n->prev=n;
}

SPEVENT_INLINEintSPEVENT_LIST_LEN(constSPEventList*l)
{
intlen=0;
constSPEventList*p=l;
while(p->next!=l){
p=p->next;
len++;
}
returnlen;
}

#defineSPEVENT_CONTAINER_OF(ptr,type,member)
((type*)((char*)(ptr)-(unsignedlong)(&((type*)0)->member)))

#defineSPEVENT_LIST_OBJ_INIT(obj){&(obj),&(obj)}

#defineSPEVENT_LIST_ENTRY(node,type,member)
SPEVENT_CONTAINER_OF(node,type,member)

#defineSPEVENT_LIST_FOR_EACH(pos,head)
for(pos=(head)->next;pos!=(head);pos=pos->next)

#defineSPEVENT_LIST_FOR_EACH_SAFE(pos,n,head)
for(pos=(head)->next,n=pos->next;pos!=(head);
pos=n,n=pos->next)

#defineSPEVENT_LIST_FOR_EACH_ENTRY(pos,head,member)
for(pos=SPEVENT_LIST_ENTRY((head)->next,typeof(*pos),member);
&pos->member!=(head);
pos=SPEVENT_LIST_ENTRY(pos->member.next,typeof(*pos),member))

#defineSPEVENT_LIST_FOR_EACH_ENTRY_SAFE(pos,n,head,member)
for(pos=SPEVENT_LIST_ENTRY((head)->next,typeof(*pos),member),
n=SPEVENT_LIST_ENTRY(pos->member.next,typeof(*pos),member);
&pos->member!=(head);
pos=n,n=SPEVENT_LIST_ENTRY(n->member.next,typeof(*n),member))

#defineSPEVENT_LIST_FIRST_ENTRY(ptr,type,member)
SPEVENT_LIST_ENTRY((ptr)->next,type,member)

#endif
  1. spevent.c文件說明:SPEvent的接口實現;整個邏輯通過鏈表的嵌套,實現了事件的管理,事件的訂閱,事件的發布。
#include"spevent.h"

staticSPEventListg_hublist={0};

staticSPEventHubNode*SPEventFindHubNode(SPEventList*list,constchar*event)
{
SPEventHubNode*hubNode=NULL;
SPEventList*node=NULL;

SPEVENT_LIST_FOR_EACH(node,list){
hubNode=SPEVENT_LIST_ENTRY(node,SPEventHubNode,hubList);
if(hubNode!=NULL&&strcmp(hubNode->event,event)==0){
returnhubNode;
}
}
returnNULL;
}

staticSPEventEventNode*SPEventFindEventNode(SPEventList*eventList,SPEventHandlehandle)
{
SPEventEventNode*eventNode=NULL;
SPEventList*node=NULL;

SPEVENT_LIST_FOR_EACH(node,eventList){
eventNode=SPEVENT_LIST_ENTRY(node,SPEventEventNode,list);
if(eventNode!=NULL&&handle==eventNode->handle){
returneventNode;
}
}
returnNULL;
}

SPEventEventNode*SPEventSubscribe(constchar*event,SPEventHandlehandle)
{
SPEventHubNode*hubNode=NULL;
SPEventEventNode*eventNode=NULL;

hubNode=SPEventFindHubNode(&g_hublist,event);
if(hubNode==NULL){
hubNode=(SPEventHubNode*)SPEVENT_MALLOC(sizeof(SPEventHubNode));
if(hubNode==NULL){
SPEVENT_PRINT("SPEVENThub(%s)mallocfailedrn",event);
returnNULL;
}
memset(hubNode->event,0,SPEVENT_EVENT_NAME_LEN);
memcpy(hubNode->event,event,strlen(event));
SPEVENT_LIST_INSERT_AFTER(&g_hublist,&(hubNode->hubList));
SPEVENT_LIST_INIT(&(hubNode->eventList));
}

eventNode=(SPEventEventNode*)SPEVENT_MALLOC(sizeof(SPEventEventNode));
if(eventNode==NULL){
SPEVENT_PRINT("SPEVENTevent(%s)mallocfailedrn",event);
returnNULL;
}
eventNode->handle=handle;
SPEVENT_LIST_INSERT_AFTER(&hubNode->eventList,&(eventNode->list));

SPEVENT_PRINT("SPEVENTevent(%s)Subscribesuccessrn",event);
returneventNode;
}

boolSPEventUnsubscribe(constchar*event,SPEventEventNode*node)
{
SPEventHubNode*hubNode=NULL;
SPEventEventNode*eventNode=NULL;

hubNode=SPEventFindHubNode(&g_hublist,event);
if(hubNode==NULL){
SPEVENT_PRINT("SPEVENThub(%s)findfailedrn",event);
returnfalse;
}
eventNode=SPEventFindEventNode(&(hubNode->eventList),node->handle);
if(eventNode==NULL){
SPEVENT_PRINT("SPEVENTevent(%s)findfailedrn",event);
returnfalse;
}
SPEVENT_LIST_REMOVE(&(eventNode->list));
SPEVENT_FREE(eventNode);
eventNode=NULL;

SPEVENT_PRINT("SPEVENTevent(%s)Unsubscribesuccessrn",event);
returntrue;
}

boolSPEventPublish(constchar*event,void*payload)
{
SPEventHubNode*hubNode=NULL;
SPEventEventNode*eventNode=NULL;
SPEventList*node=NULL;

hubNode=SPEventFindHubNode(&g_hublist,event);
if(hubNode==NULL){
SPEVENT_PRINT("SPEVENThub(%s)findfailedrn");
returnfalse;
}
SPEVENT_LIST_FOR_EACH(node,&(hubNode->eventList)){
eventNode=SPEVENT_LIST_ENTRY(node,SPEventEventNode,list);
if(eventNode->handle){
eventNode->handle(event,payload);
}
}

SPEVENT_PRINT("SPEVENTevent(%s)Publishsuccessrn",event);
returntrue;
}

voidSPEventClear(void)
{
SPEventHubNode*hubNode=NULL;
SPEventEventNode*eventNode=NULL;
SPEventList*hubList=NULL;
SPEventList*eventList=NULL;

SPEVENT_LIST_FOR_EACH(hubList,&g_hublist){
hubNode=SPEVENT_LIST_ENTRY(hubList,SPEventHubNode,hubList);
if(hubNode==NULL){
continue;
}
SPEVENT_LIST_FOR_EACH(eventList,&(hubNode->eventList)){
eventNode=SPEVENT_LIST_ENTRY(eventList,SPEventEventNode,list);
if(eventNode==NULL){
continue;
}
SPEVENT_LIST_REMOVE(&(eventNode->list));
SPEVENT_FREE(eventNode);
eventNode=NULL;
}

SPEVENT_LIST_REMOVE(&(hubNode->hubList));
SPEVENT_FREE(hubNode);
hubNode=NULL;
}
}

voidRecvtInfoDump(void)
{
SPEventHubNode*hubNode=NULL;
SPEventEventNode*eventNode=NULL;
SPEventList*hubList=NULL;
SPEventList*eventList=NULL;
inteventNodeCount=0;

SPEVENT_PRINT("SPEVENTlist:rn");

SPEVENT_LIST_FOR_EACH(hubList,&g_hublist){
hubNode=SPEVENT_LIST_ENTRY(hubList,SPEventHubNode,hubList);
if(hubNode==NULL){
continue;
}
SPEVENT_PRINT("SPEVENTevent(%s):",hubNode->event);
eventNodeCount=0;
SPEVENT_LIST_FOR_EACH(eventList,&(hubNode->eventList)){
eventNode=SPEVENT_LIST_ENTRY(eventList,SPEventEventNode,list);
if(eventNode==NULL){
continue;
}
eventNodeCount++;
}
SPEVENT_PRINT("%drn",eventNodeCount);
}
}

voidSPEventInit(void)
{
SPEVENT_LIST_INIT(&g_hublist);
}

voidSPEventDeinit(void)
{
SPEventClear();
}
  1. spevent.h文件說明:SPEvent的接口申明及SPEvent相關接口體的定義。
#ifndef__SPEVENT_H__
#define__SPEVENT_H__

#include"spevent_def.h"
typedefvoid(*SPEventHandle)(constchar*event,void*payload);

typedefstruct
{
SPEventHandlehandle;
SPEventListlist;
}SPEventEventNode;

typedefstruct
{
charevent[SPEVENT_EVENT_NAME_LEN];
SPEventListeventList;
SPEventListhubList;
}SPEventHubNode;

voidSPEventInit(void);

voidSPEventDeinit(void);

SPEventEventNode*SPEventSubscribe(constchar*event,SPEventHandlehandle);

boolSPEventUnsubscribe(constchar*event,SPEventEventNode*node);

boolSPEventPublish(constchar*event,void*payload);

voidSPEventClear(void);

voidRecvtInfoDump(void);

#endif

超精簡的SPEvent組件,實例:

#include
voidSPEventHandle1(constchar*event,void*payload)
{
SPEVENT_PRINT("Event1:%s,payload:%s",event,payload);
}

voidSPEventHandle2(constchar*event,void*payload)
{
SPEVENT_PRINT(ent2:%s,payload:%s",event,payload);
}

intmain()
{
SPEventInit();

SPEventEventNode*eventNode1=SPEventSubscribe("Rice",SPEventHandle1);
if(eventNode1!=NULL)
{
SPEventPublish("Rice","hello");
}else{
rlog_e("SPEVENTsubscribeeventfailed");
}

SPEventEventNode*eventNode2=SPEventSubscribe("Rice",SPEventHandle2);
if(eventNode2!=NULL)
{
SPEventPublish("Rice","world");
}else{
rlog_e("SPEVENTsubscribeeventfailed");
}

RecvtInfoDump();

SPEventUnsubscribe("Rice",eventNode1);

SPEventPublish("Rice","Hello world");

RecvtInfoDump();
return0;
}

  • 結果:
SPEVENTevent(Rice)Subscribesuccess
Event1:Rice,payload:hello
SPEVENTevent(Rice)Publishsuccess
SPEVENTevent(Rice)Subscribesuccess
Event2:Rice,payload:world
Event1:Rice,payload:world
SPEVENTevent(Rice)Publishsuccess
SPEVENTlist:
SPEVENTevent(Rice):2
SPEVENTevent(Rice)Unsubscribesuccess
Event2:Rice,payload:Hello world
SPEVENTevent(Rice)Publishsuccess
SPEVENTlist:
SPEVENTevent(Rice):1

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 組件
    +關注

    關注

    1

    文章

    505

    瀏覽量

    17805
  • MQTT
    +關注

    關注

    5

    文章

    649

    瀏覽量

    22435
收藏 人收藏

    評論

    相關推薦

    RabbitMQ中的發布訂閱模型

    多個消費者同時接受到,消費者接收到的信息一致。 發布訂閱模型適合于做模塊之間的異步通信。 img 適用場景 發送并記錄日志信息 springcloud的config組件里面通知配置自動更新 緩存同步
    的頭像 發表于 09-25 14:30 ?499次閱讀
    RabbitMQ中的<b class='flag-5'>發布</b><b class='flag-5'>訂閱</b>模型

    基于ArkTS語言的OpenHarmony APP應用開發:公共事件的訂閱發布

    應用程序提供訂閱發布、退訂公共事件的能力。 公共事件從系統角度可分為:系統公共事件和自定義公共事件。 系統公共事件:CES內部定義的公共事件,只有系統應用和系統服務才能發布,例如HAP安裝,更新,卸載
    發表于 09-18 13:16

    MQTT協議介紹之一:發布/訂閱

    ,Pub / Sub將正在接收消息(稱為訂戶)的另一客戶端(或更多客戶端)發送特定消息(稱為發布者)的客戶端去耦,這意味著發布者和訂閱者不了解彼此的存在,有一個第三個組件,稱為代理,由
    發表于 08-25 19:58

    Redis的發布訂閱機制

    Redis之發布訂閱機制
    發表于 06-11 13:21

    STM32F107是怎樣通過LWIP實現MQTT發布訂閱框架的呢

    怎樣通過STM32CubeMX配置STM32F107VCTx的demo呢?STM32F107是怎樣通過LWIP實現MQTT發布訂閱框架的呢?
    發表于 10-27 06:06

    NodeMCU實現訂閱發布主題

    NodeMCU實現訂閱發布主題。1、要點掃盲1.1 MQTT《MQTT協議--MQTT協議簡介及原理》《MQTT協議--MQTT協議解析》1.2 OneNET《NodeMCU學習(十)--發送數據
    發表于 11-01 08:37

    精簡的按鍵組件MultiButton概括

    Growing up’s a funny thing. Sneaks up on you.長大是件很有趣的事,不經意間就發生了。一、概括項目的倉庫大佬的精簡的軟件定時器multi_timer已經讓人眼前一亮,如今這個按鍵組件M
    發表于 02-28 11:19

    YoC組件發布開源操作指南須知

    過程中提交代碼到組件開發倉庫,直到組件功能完成。2.1.5 貢獻發布組件開發者將組件貢獻合入YoC,需要按照以下章節3進行操作。2.2 yo
    發表于 03-09 07:37

    請問esp32c3,ble mesh怎么向訂閱的分組發布消息?

    發布消息,為什么vnd_models模型不可以.有沒有更加簡單的api,直接傳訂閱分組地址就可以發布消息的?
    發表于 02-13 06:47

    請問esp32c3 ble mesh怎么向訂閱的分組發布消息?

    發布消息,為什么vnd_models模型不可以.有沒有更加簡單的api,直接傳訂閱分組地址就可以發布消息的?
    發表于 03-06 08:36

    基于SOA的發布/訂閱系統設計

    企業電子商務的迅猛發展已經改變了分布式系統的規模,傳統的基于請求/應答的點對 點、同步通信已不能滿足大規模動態分布式應用環境。基于SOA 的發布/訂閱系統模型
    發表于 07-08 08:42 ?21次下載

    鏈表的替代品Vector組件介紹

    SPEvent實際不會存在刪改的動作,顯然鏈表的優點在這個組件中無法體現優勢。
    的頭像 發表于 03-07 10:41 ?680次閱讀

    鏈表的替代品--Vector組件

    概述 在之前的一篇文章中,作者寫了一個事件組件-- 精簡訂閱發布事件組件--
    的頭像 發表于 04-06 15:39 ?504次閱讀

    發布/訂閱消息傳遞協議有哪些?為什么這類協議在物聯網應用廣泛

    發布/訂閱消息傳遞協議是一種消息傳遞模式,其中消息的發布者和訂閱者是解耦的,消息的發布者和訂閱
    的頭像 發表于 04-18 15:33 ?480次閱讀

    給我兩分鐘,搞懂發布-訂閱模式很輕松!

    什么是發布/訂閱模式?舉一個生活中常見的例子說明:小李到某房產中介提出租房需求,根據需求,房產中介將之前房東發布的出租信息提供給小李選擇,小李確定租房后,中介會將信息同步給房東知曉。這是一個典型
    的頭像 發表于 10-25 08:06 ?329次閱讀
    給我兩分鐘,搞懂<b class='flag-5'>發布</b>-<b class='flag-5'>訂閱</b>模式很輕松!