当前位置: 首页 > news >正文

单例模式指南:全局资源的安全访问

单例模式指南:全局资源的安全访问

📖 你有没有遇到过这些问题?

想象一下这些生活场景:

场景1:公司CEO

方式A:每个部门都有自己的CEO,各自发号施令
方式B:整个公司只有一个CEO,统一管理和决策

哪种方式更有效?

场景2:打印机管理

方式A:每个人都认为自己在独占打印机,同时发送任务
方式B:有一个打印机管理员,统一调度所有打印任务

哪种方式更有序?

在编程中,单例模式就像公司CEO和打印机管理员一样重要!

多个实例像多个CEO一样造成混乱:

// ❌ 多个配置管理实例,数据不一致
SystemConfig_t config1;
SystemConfig_t config2;
SystemConfig_t config3;void module_a_init(void)
{config1.sensor_type = SENSOR_DS18B20;config1.baudrate = 115200;
}void module_b_init(void)
{config2.sensor_type = SENSOR_LM35;  // 与module_a不一致!config2.baudrate = 9600;            // 与module_a不一致!
}void module_c_init(void)
{// 使用哪个配置?config1还是config2?if (config3.sensor_type == SENSOR_DS18B20) {// 可能使用了未初始化的config3}
}

单例模式像统一的CEO一样保证一致性:

// ✅ 单例模式,全局唯一的配置管理
SystemConfig_t* SystemConfig_GetInstance(void)
{static SystemConfig_t instance;static bool initialized = false;if (!initialized){// 初始化配置instance.sensor_type = SENSOR_DS18B20;instance.baudrate = 115200;instance.display_type = DISPLAY_LCD1602;initialized = true;}return &instance;
}void module_a_init(void)
{SystemConfig_t *config = SystemConfig_GetInstance();// 所有模块使用同一个配置实例
}void module_b_init(void)
{SystemConfig_t *config = SystemConfig_GetInstance();// 保证配置一致性
}

本文将详细介绍单例模式的原理和最佳实践,帮助开发者安全管理全局资源。


🎯 为什么需要单例模式?

生活中的例子

场景1:国家总统

多实例:每个州都有自己的总统,政令不统一
单例模式:一个国家只有一个总统,政令统一

场景2:数据库连接

多实例:每个模块都创建数据库连接,资源浪费
单例模式:全局共享一个连接池,资源高效利用

单例模式的价值

  1. 资源节约:避免重复创建昂贵的资源
  2. 数据一致性:全局共享同一份数据
  3. 访问控制:统一管理对共享资源的访问
  4. 协调行为:避免多个实例间的冲突

🌟 单例模式基本实现

1. 简单单例模式

基础单例实现
// simple_singleton.h - 简单单例typedef struct {float temperature_threshold;float pressure_threshold;uint32_t sample_interval_ms;bool alarm_enabled;char device_name[32];
} SystemConfig_t;// 单例接口
SystemConfig_t* SystemConfig_GetInstance(void);
bool SystemConfig_LoadFromEEPROM(void);
bool SystemConfig_SaveToEEPROM(void);
void SystemConfig_SetDefaults(void);
简单单例实现
// system_config.c - 系统配置单例static SystemConfig_t g_system_config;
static bool g_config_initialized = false;/*** @brief 获取系统配置单例* @return 系统配置实例指针*/
SystemConfig_t* SystemConfig_GetInstance(void)
{if (!g_config_initialized){// 懒加载:第一次访问时初始化SystemConfig_SetDefaults();SystemConfig_LoadFromEEPROM();g_config_initialized = true;printf("系统配置单例初始化完成\n");}return &g_system_config;
}/*** @brief 设置默认配置*/
void SystemConfig_SetDefaults(void)
{g_system_config.temperature_threshold = 85.0f;g_system_config.pressure_threshold = 1000.0f;g_system_config.sample_interval_ms = 1000;g_system_config.alarm_enabled = true;strcpy(g_system_config.device_name, "LFS-FlowMeter");printf("系统配置设置为默认值\n");
}/*** @brief 从EEPROM加载配置* @return 加载结果*/
bool SystemConfig_LoadFromEEPROM(void)
{// 检查EEPROM中是否有有效配置uint32_t magic_number;if (!EEPROM_Read(CONFIG_MAGIC_ADDR, &magic_number, sizeof(magic_number))){printf("EEPROM读取失败,使用默认配置\n");return false;}if (magic_number != CONFIG_MAGIC_VALUE){printf("EEPROM中无有效配置,使用默认配置\n");return false;}// 读取配置数据if (EEPROM_Read(CONFIG_DATA_ADDR, &g_system_config, sizeof(g_system_config))){printf("从EEPROM加载配置成功\n");return true;}printf("EEPROM配置数据损坏,使用默认配置\n");return false;
}/*** @brief 保存配置到EEPROM* @return 保存结果*/
bool SystemConfig_SaveToEEPROM(void)
{// 写入魔数uint32_t magic_number = CONFIG_MAGIC_VALUE;if (!EEPROM_Write(CONFIG_MAGIC_ADDR, &magic_number, sizeof(magic_number))){printf("EEPROM魔数写入失败\n");return false;}// 写入配置数据if (EEPROM_Write(CONFIG_DATA_ADDR, &g_system_config, sizeof(g_system_config))){printf("配置保存到EEPROM成功\n");return true;}printf("配置保存到EEPROM失败\n");return false;
}

2. 线程安全单例

多线程环境下的安全实现
// thread_safe_singleton.h - 线程安全单例typedef struct {uint32_t total_pulses;float total_volume;float instantaneous_flow;uint32_t last_update_time;bool is_measuring;
} FlowData_t;// 线程安全的流量数据单例
FlowData_t* FlowData_GetInstance(void);
void FlowData_UpdatePulse(void);
void FlowData_UpdateFlow(float flow);
void FlowData_Reset(void);
bool FlowData_StartMeasurement(void);
void FlowData_StopMeasurement(void);
线程安全实现
// flow_data_singleton.c - 流量数据单例#include "mutex.h"static FlowData_t g_flow_data;
static bool g_flow_data_initialized = false;
static Mutex_t g_flow_data_mutex;/*** @brief 获取流量数据单例(线程安全)* @return 流量数据实例指针*/
FlowData_t* FlowData_GetInstance(void)
{// 双重检查锁定模式if (!g_flow_data_initialized){Mutex_Lock(&g_flow_data_mutex);// 再次检查,防止多线程重复初始化if (!g_flow_data_initialized){memset(&g_flow_data, 0, sizeof(g_flow_data));g_flow_data.last_update_time = GetSystemTick();g_flow_data_initialized = true;printf("流量数据单例初始化完成\n");}Mutex_Unlock(&g_flow_data_mutex);}return &g_flow_data;
}/*** @brief 更新脉冲计数(线程安全)*/
void FlowData_UpdatePulse(void)
{Mutex_Lock(&g_flow_data_mutex);FlowData_t *data = FlowData_GetInstance();data->total_pulses++;data->last_update_time = GetSystemTick();Mutex_Unlock(&g_flow_data_mutex);
}/*** @brief 更新瞬时流量(线程安全)* @param flow 瞬时流量值*/
void FlowData_UpdateFlow(float flow)
{Mutex_Lock(&g_flow_data_mutex);FlowData_t *data = FlowData_GetInstance();data->instantaneous_flow = flow;// 更新累计流量(简化计算)uint32_t current_time = GetSystemTick();uint32_t time_diff = current_time - data->last_update_time;if (time_diff > 0){data->total_volume += flow * (time_diff / 60000.0f); // 转换为分钟}data->last_update_time = current_time;Mutex_Unlock(&g_flow_data_mutex);
}/*** @brief 重置流量数据(线程安全)*/
void FlowData_Reset(void)
{Mutex_Lock(&g_flow_data_mutex);FlowData_t *data = FlowData_GetInstance();data->total_pulses = 0;data->total_volume = 0.0f;data->instantaneous_flow = 0.0f;data->last_update_time = GetSystemTick();printf("流量数据已重置\n");Mutex_Unlock(&g_flow_data_mutex);
}

3. 延迟初始化单例

按需创建的单例
// lazy_singleton.c - 延迟初始化单例typedef struct {char log_buffer[LOG_BUFFER_SIZE];size_t buffer_index;bool buffer_full;uint32_t log_count;FILE *log_file;
} Logger_t;static Logger_t *g_logger_instance = NULL;
static bool g_logger_cleanup_registered = false;/*** @brief 清理日志单例*/
static void logger_cleanup(void)
{if (g_logger_instance){if (g_logger_instance->log_file){fclose(g_logger_instance->log_file);}free(g_logger_instance);g_logger_instance = NULL;printf("日志单例已清理\n");}
}/*** @brief 获取日志单例(延迟初始化)* @return 日志实例指针*/
Logger_t* Logger_GetInstance(void)
{if (g_logger_instance == NULL){g_logger_instance = malloc(sizeof(Logger_t));if (g_logger_instance == NULL){printf("日志单例创建失败:内存不足\n");return NULL;}// 初始化日志实例memset(g_logger_instance->log_buffer, 0, LOG_BUFFER_SIZE);g_logger_instance->buffer_index = 0;g_logger_instance->buffer_full = false;g_logger_instance->log_count = 0;g_logger_instance->log_file = fopen("system.log", "a");// 注册清理函数if (!g_logger_cleanup_registered){atexit(logger_cleanup);g_logger_cleanup_registered = true;}printf("日志单例创建成功\n");}return g_logger_instance;
}/*** @brief 写入日志* @param level 日志级别* @param message 日志消息*/
void Logger_Write(LogLevel_t level, const char *message)
{Logger_t *logger = Logger_GetInstance();if (logger == NULL){return;}// 格式化日志消息char formatted_msg[256];uint32_t timestamp = GetSystemTick();snprintf(formatted_msg, sizeof(formatted_msg), "[%lu] [%s] %s\n", timestamp, LogLevel_ToString(level), message);// 写入缓冲区size_t msg_len = strlen(formatted_msg);if (logger->buffer_index + msg_len < LOG_BUFFER_SIZE){strcpy(&logger->log_buffer[logger->buffer_index], formatted_msg);logger->buffer_index += msg_len;}else{logger->buffer_full = true;}// 写入文件if (logger->log_file){fprintf(logger->log_file, "%s", formatted_msg);fflush(logger->log_file);}logger->log_count++;
}

🎨 LFS项目中的单例应用

1. 系统状态管理单例

全局系统状态
// system_state_singleton.c - 系统状态单例typedef enum {SYSTEM_STATE_INITIALIZING = 0,SYSTEM_STATE_IDLE,SYSTEM_STATE_MEASURING,SYSTEM_STATE_CALIBRATING,SYSTEM_STATE_ERROR,SYSTEM_STATE_SHUTDOWN
} SystemState_t;typedef struct {SystemState_t current_state;SystemState_t previous_state;uint32_t state_enter_time;uint32_t total_runtime;uint32_t error_count;char last_error_message[64];bool maintenance_mode;
} SystemStatus_t;static SystemStatus_t g_system_status;
static bool g_status_initialized = false;/*** @brief 获取系统状态单例*/
SystemStatus_t* SystemStatus_GetInstance(void)
{if (!g_status_initialized){g_system_status.current_state = SYSTEM_STATE_INITIALIZING;g_system_status.previous_state = SYSTEM_STATE_INITIALIZING;g_system_status.state_enter_time = GetSystemTick();g_system_status.total_runtime = 0;g_system_status.error_count = 0;g_system_status.maintenance_mode = false;memset(g_system_status.last_error_message, 0, sizeof(g_system_status.last_error_message));g_status_initialized = true;printf("系统状态单例初始化完成\n");}return &g_system_status;
}/*** @brief 设置系统状态*/
void SystemStatus_SetState(SystemState_t new_state)
{SystemStatus_t *status = SystemStatus_GetInstance();if (status->current_state != new_state){status->previous_state = status->current_state;status->current_state = new_state;status->state_enter_time = GetSystemTick();printf("系统状态变更: %d -> %d\n", status->previous_state, new_state);// 记录状态变更日志Logger_Write(LOG_LEVEL_INFO, "系统状态变更");}
}/*** @brief 记录系统错误*/
void SystemStatus_RecordError(const char *error_message)
{SystemStatus_t *status = SystemStatus_GetInstance();status->error_count++;strncpy(status->last_error_message, error_message, sizeof(status->last_error_message) - 1);printf("系统错误 #%lu: %s\n", status->error_count, error_message);// 记录错误日志Logger_Write(LOG_LEVEL_ERROR, error_message);
}

2. 硬件资源管理单例

硬件资源统一管理
// hardware_manager_singleton.c - 硬件管理单例typedef struct {bool gpio_initialized;bool uart_initialized;bool adc_initialized;bool timer_initialized;uint32_t gpio_usage_mask;uint8_t uart_baudrate_index;uint8_t adc_channels_used;uint32_t timer_prescaler;// 资源锁定状态bool gpio_locked[16];bool uart_locked;bool adc_locked;bool timer_locked;
} HardwareManager_t;static HardwareManager_t g_hw_manager;
static bool g_hw_manager_initialized = false;/*** @brief 获取硬件管理器单例*/
HardwareManager_t* HardwareManager_GetInstance(void)
{if (!g_hw_manager_initialized){memset(&g_hw_manager, 0, sizeof(g_hw_manager));g_hw_manager_initialized = true;printf("硬件管理器单例初始化完成\n");}return &g_hw_manager;
}/*** @brief 申请GPIO资源*/
bool HardwareManager_RequestGPIO(uint8_t pin)
{HardwareManager_t *hw = HardwareManager_GetInstance();if (pin >= 16 || hw->gpio_locked[pin]){printf("GPIO %d 申请失败:已被占用\n", pin);return false;}hw->gpio_locked[pin] = true;hw->gpio_usage_mask |= (1 << pin);printf("GPIO %d 申请成功\n", pin);return true;
}/*** @brief 释放GPIO资源*/
void HardwareManager_ReleaseGPIO(uint8_t pin)
{HardwareManager_t *hw = HardwareManager_GetInstance();if (pin < 16 && hw->gpio_locked[pin]){hw->gpio_locked[pin] = false;hw->gpio_usage_mask &= ~(1 << pin);printf("GPIO %d 已释放\n", pin);}
}/*** @brief 申请UART资源*/
bool HardwareManager_RequestUART(uint32_t baudrate)
{HardwareManager_t *hw = HardwareManager_GetInstance();if (hw->uart_locked){printf("UART申请失败:已被占用\n");return false;}hw->uart_locked = true;hw->uart_baudrate_index = GetBaudrateIndex(baudrate);printf("UART申请成功,波特率: %lu\n", baudrate);return true;
}

📚 参考资料

设计模式

  1. Singleton Pattern - 单例模式详解
  2. Thread-Safe Singleton - 线程安全单例
  3. Double-Checked Locking - 双重检查锁定
  4. Lazy Initialization - 延迟初始化

嵌入式应用

  1. C语言编程规范 - Linux内核编码风格
  2. 嵌入式C语言最佳实践 - GitHub开源编码规范
  3. 单例模式讨论 - Stack Overflow
  4. FreeRTOS官方文档 - 实时操作系统

🏷️ 总结

单例模式就像国家元首

  • 全局唯一确保权威性和一致性
  • 统一访问提供标准化的服务接口
  • 资源控制避免重复创建和资源浪费
  • 状态共享维护全局一致的状态信息

核心原则

  1. 全局唯一 > 多个实例
  2. 延迟创建 > 提前创建
  3. 线程安全 > 竞态条件
  4. 资源控制 > 随意访问

记住这个公式

优秀的单例模式 = 全局唯一 + 延迟创建 + 线程安全 + 资源控制

通过本文的学习,我们了解了单例模式的原理和最佳实践,掌握了安全管理全局资源的方法。


单例模式是全局资源的守护者,让你的代码像有序的王国一样运行! 🔒

http://www.dtcms.com/a/394791.html

相关文章:

  • 容器化 Tomcat 应用程序
  • Vue Router【前端】
  • 数据结构——受限线性表之栈
  • 数据结构(1)------ 三要素
  • BaaS(Backend as a Service)概述、平台、项目
  • 区间dp,数据结构优化dp等5种dp,各种trick深度讲解
  • 数据结构笔试选择题:题组1
  • 前端基础:从0到1实现简单网页效果(一)
  • 数据结构|图论:从数据结构到工程实践的核心引擎
  • AI赋能个人效能提升:实战演练工作规划、项目复盘与学习发展
  • 7. Linux RAID 存储技术
  • iOS 上架 App 费用详解 苹果应用发布成本、App Store 上架收费标准、开发者账号与审核实战经验
  • kafka 2.12_3.9.1 版本修复 Apache Commons BeanUtils 访问控制错误漏洞(CVE-2025-48734)
  • 二分查找经典——力扣153.寻找旋转排序数组中的最小值
  • 离散数学之命题逻辑
  • 【Linux命令从入门到精通系列指南】ping 命令详解:网络连通性诊断的终极工具
  • 游戏UI告别“贴图”时代:用Adobe XD构建“活”的设计系统
  • NXP - 用MCUXpresso IDE导入lpcopen_2_10_lpcxpresso_nxp_lpcxpresso_1769.zip中的工程
  • ✅ Python+Django租房推荐系统 双协同过滤+Echarts可视化 租房系统 推荐算法 全栈开发(建议收藏)✅
  • Django入门-3.公共视图
  • 【 设计模式 | 结构型模式 代理模式 】
  • 小杰机器学习高级(five)——分类算法的评估标准
  • IS-IS 中同时收到 L1 和 L2 的 LSP 时,是否优选 L1
  • 【开源】基于STM32的智能车尾灯
  • 电子电气架构 --- 软件开发与产品系统集成流程(下)
  • Ubuntu系统目录架构是怎么样的
  • 自动驾驶仿真之“场景交互”技术研究
  • 《AI管家还是数字化身?—— 一种面向未来的个人智能架构构想》
  • AI提升工业生产制造安全,基于YOLOv9全系列【yolov9/t/s/m/c/e】参数模型开发构建工业生产制造加工场景下工业设备泄漏智能化检测识别预警系统
  • 深度学习(十一):深度神经网络和前向传播