推荐一个嵌入式轻量级事件管理库!

在嵌入式开发领域,当需要高效利用有限资源或应对大量异步操作时,采用事件驱动架构能显著提升系统的性能和可靠性。

本次推荐一个轻量级事件管理库——lwevt

lwevt 简介

基本介绍

https://github.com/MaJerle/lwevt

lwevt 是一款专为嵌入式系统打造的轻量级事件管理库,基于 C 语言开发。它的设计目标是提供高效、简洁的事件处理机制,帮助开发者快速实现事件驱动的应用程序。

该库具有良好的跨平台性,能够在多种嵌入式操作系统和硬件平台上稳定运行,为嵌入式设备的事件管理提供了可靠的解决方案。

特性

  • 独立于平台,没有特定的架构代码
  • 灵活的应用程序定义的事件类型和相关数据
  • 易于使用和维护
  • 用户友好的MIT许可

lwevt 使用

下载源码:

git clone --recurse-submodules https://github.com/MaJerle/lwevt

下面演示lvevt的使用:

#include <stdio.h>
#include <string.h>
#include "lwevt/lwevt.h"

static void prv_evt_fn_1(lwevt_t* e) {
    switch ((unsigned)e->type){
        case LWEVT_TYPE_MY_EXT_1: {
            printf("Event fn 1, LWEVT_TYPE_MY_EXT_1 - with data: a: %d, b: %d\r\n",
                (int)e->msg.a.a, (int)e->msg.a.b);
            break;
        }
        default:
            break;
    }
}

static void prv_evt_fn_2(lwevt_t* e) {
    switch ((unsigned)e->type){
        case LWEVT_TYPE_MY_EXT_2: {
            printf("Event fn 2, LWEVT_TYPE_MY_EXT_2 - with data: a: %d, b: %d\r\n",
                (int)e->msg.b.a, (int)e->msg.b.a);
            break;
        }
        default:
            break;
    }
}

int main(void) {
    lwevt_t* evt;
    lwevt_t evt_local;

    // 初始化事件系统
    lwevt_init();

    // 注册两个用户事件监听器
    lwevt_register(prv_evt_fn_1);
    lwevt_register(prv_evt_fn_2);
    
    evt = lwevt_get_handle();   // 获取默认事件句柄
    evt->msg.a.a = 1;           
    evt->msg.a.b = 2;           
    lwevt_dispatch(LWEVT_TYPE_MY_EXT_1);  // 分发事件,所有监听器都会收到

    evt_local.msg.b.a = 3;    
    evt_local.msg.b.b = 4;    
    lwevt_dispatch_ex(&evt_local, LWEVT_TYPE_MY_EXT_2);  // 用本地句柄分发事件
    
    return 0;
}

为了优化内存消耗,在LwEVT中将主事件句柄定义为静态全局变量。它可以通过lwevt_get_handle()函数访问,并允许使用默认的lwevt_dispatch()函数分发事件。

lwevt_get_handle()和lwevt_dispatch()只有当
LWEVT_CFG_ENABLE_DEFAULT_HANDLE(
lwevt/src/include/lwevt/lwevt_opt.h)被启用时才可用。

在多线程环境中,应用程序必须保证get句柄和dispatch调用之间的线程安全。

为了避免使用信号量或互斥锁,可以定义基于lwevt_t的本地变量,并使用lwevt_dispatch_ex()函数分发事件。

在LwEVT中,事件类型和事件数据的定义采用了X-Macro技术。

在 C 语言中,X-Macro 技术是一种利用预处理宏(Preprocessor Macro)实现代码复用与一致性维护的编程技巧。它的核心思想是:将一组相关的数据或结构以 “宏列表” 的形式定义,然后通过重新定义宏的展开方式,在不同场景下对这组数据进行不同形式的处理,从而避免重复编写相似代码,同时保证数据与相关操作的一致性。

使得事件类型和事件数据可以通过单独的lwevt_types.h文件来维护,如lwevt_types.h的内容可以根据需要自定义定义事件类型及事件数据:

LWEVT_TYPE_BASIC(LWEVT_TYPE_MY_BASIC_1)
LWEVT_TYPE_BASIC(LWEVT_TYPE_MY_BASIC_2)
LWEVT_TYPE_BASIC(LWEVT_TYPE_MY_BASIC_3)
LWEVT_TYPE_EXT(
    LWEVT_TYPE_MY_EXT_1, struct {
        int a;
        int b;
    } a)
LWEVT_TYPE_EXT(
    LWEVT_TYPE_MY_EXT_2, struct {
        int a;
        int b;
    } b)
LWEVT_TYPE_EXT(
    LWEVT_TYPE_MY_EXT_3, struct {
        int a;
        int b;
    } c)

/* Add more types here ... */

lwevt.h采用了X-Macro技术定义LwEVT的核心接口和数据结构,主要内容如下:

事件类型定义

typedef enum {
#define LWEVT_TYPE_BASIC(name)     name,
#define LWEVT_TYPE_EXT(name, data) name,
#include "lwevt/lwevt_type.h"
    LWEVT_TYPE_LAST
} lwevt_type_t;

lwevt_type.h:

#ifndef LWEVT_TYPE_BASIC
#define LWEVT_TYPE_BASIC(name)
#endif

#ifndef LWEVT_TYPE_EXT
#define LWEVT_TYPE_EXT(name, data)
#endif

/* Include user types */
#include "lwevt_types.h"

/* Undefine type back - after use */
#undef LWEVT_TYPE_BASIC
#undef LWEVT_TYPE_EXT

事件类型通过宏展开和 lwevt_type.h 文件定义,支持扩展。

事件结构体

typedef struct {
    lwevt_type_t type; // 事件类型
    union {
#define LWEVT_TYPE_EXT(name, data) data;
#include "lwevt/lwevt_type.h"
        const unsigned int dummy;
    } msg; // 事件消息体,支持扩展数据
} lwevt_t;
  • type 字段标识事件类型。
  • msg 联合体用于存储扩展事件的数据(通过宏和 lwevt_type.h 支持多种事件数据结构)。
原文链接:,转发请注明来源!