一、單例模式
單例模式(Singleton Pattern)確保一個類僅有一個實例,并提供全局訪問點。
單例模式核心結構圖:
結構通常包括:
- 一個私有靜態實例(指向自身的指針)
- 一個私有構造函數(防止外部創建實例)
- 一個公共的靜態方法(用于獲取唯一實例)
在嵌入式系統中,該模式尤其適用于:
- 全局狀態:系統配置、錯誤日志
- 硬件外設管理:SPI/I2C控制器
- 資源池:內存池、連接池
- 核心管理器:電源管理、安全控制器
嵌入式設計要點:
- 線程安全:需通過關中斷、互斥鎖保護臨界區(尤其在RTOS中)。
- 無動態內存:優先靜態分配實例,避免堆內存碎片。
二、嵌入式應用案例
一個遠程監控系統的系統狀態維護。
- 非單例模式:每個模塊(傳感器模塊、控制模塊、通信模塊)各自維護系統狀態,導致:
- 溫度傳感器認為系統正常
- 但控制模塊檢測到故障
- 狀態不一致引發危險操作
- 單例模式:建立中央控制臺(唯一實例),所有模塊通過它訪問系統狀態,確保全局決策一致。
1、代碼實現:
C語言:
#include
#include
// 全局狀態結構體
typedefstruct {
int system_mode;
int error_code;
unsignedlong operation_count;
} SystemState;
// 單例狀態管理器
typedefstruct {
SystemState state;
pthread_mutex_t lock;
} StateManager;
// 全局單例實例
static StateManager* instance = NULL;
// 獲取單例實例(線程安全)
StateManager* get_state_manager() {
if (instance == NULL) {
// 創建互斥鎖
staticpthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&init_lock);
if (instance == NULL) {
static StateManager manager;
manager.state.system_mode = 0;
manager.state.error_code = 0;
manager.state.operation_count = 0;
pthread_mutex_init(&manager.lock, NULL);
instance = &manager;
}
pthread_mutex_unlock(&init_lock);
}
return instance;
}
// 設置系統模式
void set_system_mode(int mode) {
StateManager* manager = get_state_manager();
pthread_mutex_lock(&manager->lock);
manager->state.system_mode = mode;
pthread_mutex_unlock(&manager->lock);
}
// 獲取系統模式
int get_system_mode() {
StateManager* manager = get_state_manager();
pthread_mutex_lock(&manager->lock);
int mode = manager->state.system_mode;
pthread_mutex_unlock(&manager->lock);
return mode;
}
// 報告錯誤
void report_error(int error_code) {
StateManager* manager = get_state_manager();
pthread_mutex_lock(&manager->lock);
manager->state.error_code = error_code;
pthread_mutex_unlock(&manager->lock);
}
// 增加操作計數
void increment_operation_count() {
StateManager* manager = get_state_manager();
pthread_mutex_lock(&manager->lock);
manager->state.operation_count++;
pthread_mutex_unlock(&manager->lock);
}
// 打印系統狀態
void print_system_state() {
StateManager* manager = get_state_manager();
pthread_mutex_lock(&manager->lock);
printf("\n=== 系統狀態 ===\n");
printf("當前模式: %s\n",
manager->state.system_mode == 0 ? "正常模式" :
manager->state.system_mode == 1 ? "維護模式" : "緊急模式");
printf("錯誤代碼: 0x%04X\n", manager->state.error_code);
printf("操作計數: %lu\n", manager->state.operation_count);
pthread_mutex_unlock(&manager->lock);
}
// 模擬傳感器模塊
void* sensor_module(void* arg) {
printf("傳感器啟動...\n");
for (int i = 0; i < 3; i++) {
increment_operation_count();
printf("傳感器檢測中...\n");
sleep(1);
}
returnNULL;
}
// 模擬控制模塊
void* control_module(void* arg) {
printf("控制器啟動...\n");
sleep(1);
// 模擬檢測到錯誤
report_error(0xE1A2);
set_system_mode(2); // 進入緊急模式
printf("控制器檢測到嚴重錯誤!\n");
returnNULL;
}
int main() {
printf("=== 控制系統啟動 ===\n");
// 初始化狀態管理器
get_state_manager();
print_system_state();
// 創建模擬線程
pthread_t sensor_thread, control_thread;
pthread_create(&sensor_thread, NULL, sensor_module, NULL);
pthread_create(&control_thread, NULL, control_module, NULL);
// 等待線程完成
pthread_join(sensor_thread, NULL);
pthread_join(control_thread, NULL);
// 打印最終狀態
print_system_state();
printf("\n=== 系統關閉 ===\n");
return0;
}
在C語言中,沒有類的概念,因此我們通過靜態全局變量和函數來模擬單例模式。
- 私有靜態實例:靜態全局指針
static StateManager* instance = NULL;
,它指向唯一的實例。而實例本身是在獲取函數內部使用靜態局部變量static StateManager manager;
來創建的。這樣,實例在程序運行期間只被初始化一次,并且通過指針返回。 - 私有構造函數:在C中,通過靜態初始化或在獲取函數內部初始化來實現。在
get_state_manager()
函數中,通過靜態局部變量來創建實例,并只做一次初始化 - 公共的靜態方法:即
get_state_manager()
函數,它返回單例實例的指針。同時,我們還提供了其他操作狀態的函數,如set_system_mode()
,get_system_mode()
等,這些函數內部都會調用get_state_manager()
來獲取單例實例。
C++:
#include
#include
#include
#include
class StateManager {
private:
struct State {
int system_mode = 0;
int error_code = 0;
unsignedlong operation_count = 0;
} state;
std::mutex mtx; // 非靜態成員鎖,保護實例狀態
StateManager() = default; // 私有構造函數
public:
// 刪除拷貝構造函數和賦值運算符
StateManager(const StateManager&) = delete;
voidoperator=(const StateManager&) = delete;
// 使用局部靜態變量實現線程安全的單例
static StateManager& getInstance() {
static StateManager instance;
return instance;
}
void setSystemMode(int mode) {
std::lock_guard lock(mtx);
state.system_mode = mode;
state.operation_count++;
}
int getSystemMode() {
std::lock_guard lock(mtx);
return state.system_mode;
}
void printState() {
std::lock_guard lock(mtx);
std::cout << "Mode: " << state.system_mode
<< " | Errors: 0x" << std::hex << state.error_code
<< " | Operations: " << std::dec << state.operation_count << "\n";
}
};
// 測試函數
void threadTask(int mode) {
StateManager& manager = StateManager::getInstance();
manager.setSystemMode(mode);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
manager.printState();
}
int main() {
std::vector threads;
// 創建多個線程測試線程安全
for (int i = 1; i <= 5; ++i) {
threads.emplace_back(threadTask, i);
}
// 等待所有線程完成
for (auto& t : threads) {
t.join();
}
// 主線程訪問
StateManager::getInstance().printState();
return0;
}
2、優缺點
優點:
(1)資源高效性:
- 內存節省:僅一個實例,減少重復對象占用的RAM(關鍵于資源受限MCU)。
- 性能提升:避免頻繁創建/銷毀對象(如通信協議棧),降低CPU開銷。
(2)行為一致性:
- 防止硬件狀態沖突(如多任務同時配置UART波特率)。
- 確保全局數據(如校準參數)唯一可信。
缺點:
(1)擴展性差:缺乏抽象層,難以通過繼承擴展功能(違反開閉原則)。
(2)生命周期問題:靜態實例長期占用內存,若未被利用則浪費資源。