观察者模式在 RT-Thread 中的实现 | 技术集结

描述

在嵌入式系统中,模块间的高耦合和轮询机制往往带来资源浪费与响应延迟。观察者模式通过“发布-订阅”机制,能够以轻量级方式实现模块解耦与事件驱动。本文结合传感器更新、系统状态变化等典型场景,对比事件通知机制,并给出C语言代码实现,帮助开发者高效应用观察者模式。

目录

 


 

为啥要使用观察者模式


 

场景举例


 

观察者模式在嵌入式中的核心优点


 

观察者模式和事件通知对比


 

观察者模式代码实现

1 为啥要使用观察者模式

为了解决嵌入式系统中常见的 模块解耦、事件驱动、低功耗响应 等核心问题。虽然 C 语言没有类和继承,但通过函数指针和结构体,完全可以轻量级实现观察者模式

2 场景举例

传感器数据更新

温度传感器每 500ms 采样一次

多个模块关心这个值:LCD 显示、日志记录、云端上报、过温告警

若每个模块都轮询读取 → 浪费 CPU、代码耦合高

用观察者模式:传感器“发布”数据,各模块“订阅” → 事件驱动、按需响应

系统状态变化通知

网络连接状态(断开/重连)

电池电量低

OTA 升级完成

多个业务模块需做出反应(如 UI 刷新、保存上下文、关闭外设)

硬件中断与业务逻辑分离

按键中断触发 → 不能在 ISR 中做复杂处理

通过观察者通知应用层任务 → 安全、可扩展

3 观察者模式在嵌入式中的核心优点

嵌入式系统

4 观察者模式和事件通知对比

4.1 功能特性对比

嵌入式系统

4.2 使用场景分析

4.2.1 观察者模式适用场景

  •  
  •  
  •  
  •  
  •  
  •  

// 1. 传感器数据变化通知多个处理模块 sensor_subject.notify(sensor_data); // 2. 系统状态变化广播 system_state_subject.notify(new_state); // 3. 配置参数更新通知 config_subject.notify(changed_params);

4.2.2 事件通知适用场景

  •  
  •  
  •  
  •  
  •  
  •  

// 1. 线程间同步等待特定条件 rt_event_recv(event, EVENT_DATA_READY, RT_EVENT_FLAG_AND, timeout, &recved); // 2. 多个事件源的组合条件等待 rt_event_recv(event, EVENT_A | EVENT_B, RT_EVENT_FLAG_OR, timeout, &recved); // 3. 异步任务完成通知 rt_event_send(task_event, TASK_COMPLETED);

4.3 性能特点对比

观察者模式优势:

即时通知:无需等待,直接回调执行

数据丰富:可传递复杂数据结构指针

解耦性好:观察者与被观察者松耦合

扩展性强:易于添加新的观察者类型

事件通知优势:

标准IPC:符合RT-Thread IPC规范

阻塞等待:支持超时和非阻塞模式

条件组合:AND/OR逻辑组合等待

系统集成:与其他IPC机制统一管理

4.4 选择建议

选择观察者模式当:

需要立即响应状态变化

要传递复杂的数据结构

构建松耦合的组件架构

实现发布-订阅模式

选择事件通知当:

需要线程间同步等待

要求阻塞或超时机制

处理多种事件源的组合条件

利用RT-Thread标准IPC机制

5 观察者模式代码实现

observer.c

  •  
  •  
  •  
  •  
  •  

/** * @file observer.c * @brief 观察者模式实现文件 * @author  * @version 1.0 * @date 2026-02-10 * * 基于RT-Thread rt_list实现的观察者模式具体实现 */#include"observer.h"#define DBG_TAG               "OBSERVER"#define DBG_LVL               DBG_INFO#include/** * @brief 初始化被观察者 */rt_err_tsubject_init(subject_t *subject){    RT_ASSERT(subject != RT_NULL);    /* 初始化观察者链表 */    rt_list_init(&subject->observer_list);    /* 运行时初始化自旋锁 */    rt_spin_lock_init(&subject->lock);    LOG_D("Subject initialized");    return RT_EOK;}/** * @brief 添加观察者 */rt_err_tsubject_add_observer(subject_t *subject, observer_t *observer){    rt_base_t level;    RT_ASSERT(subject != RT_NULL);    RT_ASSERT(observer != RT_NULL);    RT_ASSERT(observer->update != RT_NULL);    /* 关闭中断并获取自旋锁 */    level = rt_spin_lock_irqsave(&subject->lock);    /* 检查观察者是否已经存在 */    rt_list_t *node;    rt_list_for_each(node, &subject->observer_list)    {        observer_t *existing_observer = rt_list_entry(node, observer_t, list);        if (existing_observer == observer)        {            rt_spin_unlock_irqrestore(&subject->lock, level);            LOG_W("Observer already exists");            return -RT_ERROR;        }    }    /* 添加观察者到链表尾部 */    rt_list_insert_before(&subject->observer_list, &observer->list);    /* 恢复中断并释放自旋锁 */    rt_spin_unlock_irqrestore(&subject->lock, level);    LOG_D("Observer added");    return RT_EOK;}/** * @brief 移除观察者 */rt_err_tsubject_remove_observer(subject_t *subject, observer_t *observer){    rt_base_t level;    rt_err_t result = -RT_ERROR;    RT_ASSERT(subject != RT_NULL);    RT_ASSERT(observer != RT_NULL);    /* 关闭中断并获取自旋锁 */    level = rt_spin_lock_irqsave(&subject->lock);    /* 在链表中查找并移除观察者 */    rt_list_t *node, *temp;    rt_list_for_each_safe(node, temp, &subject->observer_list)    {        observer_t *existing_observer = rt_list_entry(node, observer_t, list);        if (existing_observer == observer)        {            rt_list_remove(node);            result = RT_EOK;            break;        }    }    /* 恢复中断并释放自旋锁 */    rt_spin_unlock_irqrestore(&subject->lock, level);    if (result == RT_EOK)    {        LOG_D("Observer removed");    }    else    {        LOG_W("Observer not found");    }    return result;}/** * @brief 通知所有观察者 */voidsubject_notify(subject_t *subject, void *data){    rt_base_t level;    RT_ASSERT(subject != RT_NULL);    /* 关闭中断并获取自旋锁 */    level = rt_spin_lock_irqsave(&subject->lock);    /* 遍历所有观察者并调用更新函数 */    rt_list_t *node, *temp;    rt_list_for_each_safe(node, temp, &subject->observer_list)    {        observer_t *observer = rt_list_entry(node, observer_t, list);        if (observer->update != RT_NULL)        {            /* 恢复中断后再调用回调函数,避免在中断上下文中执行用户代码 */            rt_spin_unlock_irqrestore(&subject->lock, level);            observer->update(observer, subject, data);            level = rt_spin_lock_irqsave(&subject->lock);        }    }    /* 恢复中断并释放自旋锁 */    rt_spin_unlock_irqrestore(&subject->lock, level);    LOG_D("All observers notified");}/** * @brief 初始化观察者 */rt_err_tobserver_init(observer_t *observer, observer_update_func_t update, void *user_data){    RT_ASSERT(observer != RT_NULL);    RT_ASSERT(update != RT_NULL);    /* 初始化链表节点 */    rt_list_init(&observer->list);    /* 设置回调函数和用户数据 */    observer->update = update;    observer->user_data = user_data;    LOG_D("Observer initialized");    return RT_EOK;}/** * @brief 获取观察者数量 */intsubject_get_observer_count(subject_t *subject){    rt_base_t level;    int count = 0;    RT_ASSERT(subject != RT_NULL);    /* 关闭中断并获取自旋锁 */    level = rt_spin_lock_irqsave(&subject->lock);    /* 统计观察者数量 */    rt_list_t *node;    rt_list_for_each(node, &subject->observer_list)    {        count++;    }    /* 恢复中断并释放自旋锁 */    rt_spin_unlock_irqrestore(&subject->lock, level);    return count;}

observer.h

  •  
  •  
  •  
  •  
  •  

/** * @file observer.h * @brief 观察者模式头文件 * @author  * @version 1.0 * @date 2026-02-10 * * 基于RT-Thread rt_list实现的观察者模式 * 支持添加观察者、移除观察者、通知观察者等功能 */#ifndef __OBSERVER_H__#define __OBSERVER_H__#include#include#ifdef __cplusplusextern"C" {#endif/** * @brief 观察者更新回调函数类型 *  * @param observer 观察者指针 * @param subject 被观察者指针 * @param data 传递的数据 */typedefvoid(*observer_update_func_t)(void *observer, void *subject, void *data);/** * @brief 观察者结构体 */typedefstructobserver{    rt_list_tlist;                     /**< 链表节点,用于串连观察者 */    observer_update_func_t update;      /**< 更新回调函数 */    void *user_data;                    /**< 用户自定义数据 */} observer_t;/** * @brief 被观察者结构体 */typedefstructsubject{    rt_list_t observer_list;            /**< 观察者链表头 */    structrt_spinlocklock;            /**< 自旋锁,保护观察者链表 */} subject_t;/** * @brief 初始化被观察者 *  * @param subject 被观察者对象指针 * @return rt_err_t RT_EOK表示成功,其他表示失败 */rt_err_tsubject_init(subject_t *subject);/** * @brief 添加观察者 *  * @param subject 被观察者对象指针 * @param observer 观察者对象指针 * @return rt_err_t RT_EOK表示成功,其他表示失败 */rt_err_tsubject_add_observer(subject_t *subject, observer_t *observer);/** * @brief 移除观察者 *  * @param subject 被观察者对象指针 * @param observer 观察者对象指针 * @return rt_err_t RT_EOK表示成功,其他表示失败 */rt_err_tsubject_remove_observer(subject_t *subject, observer_t *observer);/** * @brief 通知所有观察者 *  * @param subject 被观察者对象指针 * @param data 传递给观察者的数据 */voidsubject_notify(subject_t *subject, void *data);/** * @brief 初始化观察者 *  * @param observer 观察者对象指针 * @param update 更新回调函数 * @param user_data 用户自定义数据 * @return rt_err_t RT_EOK表示成功,其他表示失败 */rt_err_tobserver_init(observer_t *observer, observer_update_func_t update, void *user_data);/** * @brief 获取观察者数量 *  * @param subject 被观察者对象指针 * @return int 观察者数量 */intsubject_get_observer_count(subject_t *subject);#ifdef __cplusplus}#endif#endif/* __OBSERVER_H__ */

observer_demo.c

  •  
  •  
  •  
  •  
  •  

/** * @file observer_example.c * @brief 观察者模式使用示例 * @author  * @version 1.0 * @date 2026-02-10 * * 演示如何使用基于RT-Thread rt_list的观察者模式 */#include"observer.h"#include#define DBG_TAG               "OBS_EX"#define DBG_LVL               DBG_LOG#include/* 定义一个具体的数据结构作为被观察对象 */typedefstruct{    subject_t subject;          /* 继承被观察者 */    int temperature;           /* 温度数据 */    int humidity;              /* 湿度数据 */} sensor_data_t;/* 定义观察者类型 */typedefstruct{    observer_t observer;       /* 继承观察者 */    char name[32];            /* 观察者名称 */} sensor_observer_t;/* 观察者1的更新回调函数 */staticvoidtemperature_observer_update(void *observer, void *subject, void *data){    sensor_observer_t *temp_observer = (sensor_observer_t *)observer;    sensor_data_t *sensor_data = (sensor_data_t *)subject;    rt_kprintf("Temperature Observer [%s]: Temperature = %d°C, Humidity = %d%%\n",                temp_observer->name, sensor_data->temperature, sensor_data->humidity);}/* 观察者2的更新回调函数 */staticvoidhumidity_observer_update(void *observer, void *subject, void *data){    sensor_observer_t *humi_observer = (sensor_observer_t *)observer;    sensor_data_t *sensor_data = (sensor_data_t *)subject;    rt_kprintf("Humidity Observer [%s]: Temperature = %d°C, Humidity = %d%%\n",                humi_observer->name, sensor_data->temperature, sensor_data->humidity);}/* 观察者3的更新回调函数 */staticvoiddisplay_observer_update(void *observer, void *subject, void *data){    sensor_observer_t *display_observer = (sensor_observer_t *)observer;    sensor_data_t *sensor_data = (sensor_data_t *)subject;    rt_kprintf("Display Observer [%s]: Updating display with T=%d°C, H=%d%%\n",                display_observer->name, sensor_data->temperature, sensor_data->humidity);}/* 测试函数 */staticvoidobserver_test(void){    /* 创建被观察者 */    sensor_data_t sensor_data;    sensor_data.temperature = 25;    sensor_data.humidity = 60;    /* 初始化被观察者 */    if (subject_init(&sensor_data.subject) != RT_EOK)    {        LOG_E("Failed to initialize subject");        return;    }    /* 创建观察者 */    sensor_observer_t temp_observer;    sensor_observer_t humi_observer;    sensor_observer_t display_observer;    /* 初始化观察者 */    rt_strncpy(temp_observer.name, "TempMonitor", sizeof(temp_observer.name));    if (observer_init(&temp_observer.observer, temperature_observer_update, RT_NULL) != RT_EOK)    {        LOG_E("Failed to initialize temperature observer");        return;    }    rt_strncpy(humi_observer.name, "HumiMonitor", sizeof(humi_observer.name));    if (observer_init(&humi_observer.observer, humidity_observer_update, RT_NULL) != RT_EOK)    {        LOG_E("Failed to initialize humidity observer");        return;    }    rt_strncpy(display_observer.name, "DisplayCtrl", sizeof(display_observer.name));    if (observer_init(&display_observer.observer, display_observer_update, RT_NULL) != RT_EOK)    {        LOG_E("Failed to initialize display observer");        return;    }    LOG_I("=== Observer Pattern Test Start ===");    /* 添加观察者 */    LOG_I("Adding observers...");    subject_add_observer(&sensor_data.subject, &temp_observer.observer);    subject_add_observer(&sensor_data.subject, &humi_observer.observer);    subject_add_observer(&sensor_data.subject, &display_observer.observer);    LOG_I("Current observer count: %d", subject_get_observer_count(&sensor_data.subject));    /* 模拟数据变化并通知观察者 */    LOG_I("\n--- Test 1: Initial data notification ---");    subject_notify(&sensor_data.subject, RT_NULL);    LOG_I("\n--- Test 2: Temperature change ---");    sensor_data.temperature = 28;    subject_notify(&sensor_data.subject, RT_NULL);    LOG_I("\n--- Test 3: Humidity change ---");    sensor_data.humidity = 65;    subject_notify(&sensor_data.subject, RT_NULL);    LOG_I("\n--- Test 4: Both changes ---");    sensor_data.temperature = 30;    sensor_data.humidity = 70;    subject_notify(&sensor_data.subject, RT_NULL);    /* 移除一个观察者 */    LOG_I("\n--- Test 5: Remove temperature observer ---");    subject_remove_observer(&sensor_data.subject, &temp_observer.observer);    LOG_I("Observer count after removal: %d", subject_get_observer_count(&sensor_data.subject));    LOG_I("\n--- Test 6: Notify remaining observers ---");    sensor_data.temperature = 22;    sensor_data.humidity = 55;    subject_notify(&sensor_data.subject, RT_NULL);    /* 尝试重复添加同一个观察者 */    LOG_I("\n--- Test 7: Try to add duplicate observer ---");    if (subject_add_observer(&sensor_data.subject, &humi_observer.observer) != RT_EOK)    {        LOG_W("Duplicate observer rejected as expected");    }    /* 尝试移除不存在的观察者 */    LOG_I("\n--- Test 8: Try to remove non-existent observer ---");    sensor_observer_t fake_observer;    observer_init(&fake_observer.observer, temperature_observer_update, RT_NULL);    if (subject_remove_observer(&sensor_data.subject, &fake_observer.observer) != RT_EOK)    {        LOG_W("Non-existent observer removal failed as expected");    }    LOG_I("\n=== Observer Pattern Test Complete ===");}/* 在FinSH中导出测试命令 */MSH_CMD_EXPORT(observer_test, test observer pattern implementation);

测试
 

  •  
  •  
  •  
  •  
  •  

msh />observer_test[12930] V/OBS_EX tshell: === Observer Pattern Test Start ===[12937] V/OBS_EX tshell: Adding observers...[12942] V/OBS_EX tshell: Current observer count: 3[12947] V/OBS_EX tshell:--- Test 1: Initial data notification ---Temperature Observer [TempMonitor]: Temperature = 25°C, Humidity = 60%Humidity Observer [HumiMonitor]: Temperature = 25°C, Humidity = 60%Display Observer [DisplayCtrl]: Updating display with T=25°C, H=60%[12972] V/OBS_EX tshell:--- Test 2: Temperature change ---Temperature Observer [TempMonitor]: Temperature = 28°C, Humidity = 60%Humidity Observer [HumiMonitor]: Temperature = 28°C, Humidity = 60%Display Observer [DisplayCtrl]: Updating display with T=28°C, H=60%[12997] V/OBS_EX tshell:--- Test 3: Humidity change ---Temperature Observer [TempMonitor]: Temperature = 28°C, Humidity = 65%Humidity Observer [HumiMonitor]: Temperature = 28°C, Humidity = 65%Display Observer [DisplayCtrl]: Updating display with T=28°C, H=65%[13022] V/OBS_EX tshell:--- Test 4: Both changes ---Temperature Observer [TempMonitor]: Temperature = 30°C, Humidity = 70%Humidity Observer [HumiMonitor]: Temperature = 30°C, Humidity = 70%Display Observer [DisplayCtrl]: Updating display with T=30°C, H=70%[13046] V/OBS_EX tshell:--- Test 5: Remove temperature observer ---[13053] V/OBS_EX tshell: Observer count after removal: 2[13059] V/OBS_EX tshell:--- Test 6: Notify remaining observers ---Humidity Observer [HumiMonitor]: Temperature = 22°C, Humidity = 55%Display Observer [DisplayCtrl]: Updating display with T=22°C, H=55%[13078] V/OBS_EX tshell:--- Test 7: Try to add duplicate observer ---[13086] W/OBSERVER tshell: Observer already exists[13091] W/OBS_EX tshell: Duplicate observer rejected as expected[13098] V/OBS_EX tshell:--- Test 8: Try to remove non-existent observer ---[13105] W/OBSERVER tshell: Observer not found[13110] W/OBS_EX tshell: Non-existent observer removal failed as expected[13118] V/OBS_EX tshell:=== Observer Pattern Test Complete ===

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分