共享數據的競爭問題
- 問題:保護中斷與主程序共享的avg_data
- 方法一:使用關中斷保護
- 1. 添加關中斷宏
- 2. 修改數據讀取代碼
- 3. 修改中斷服務程序(ISR)
- 方法二:使用原子操作(需平臺支持)
- 1. 定義原子類型
- 2. 修改數據訪問代碼
- 方法三:使用RTOS同步機制(如信號量)
- 1. 擴展通道結構體
- 2. 初始化信號量
- 3. 保護數據訪問
- 方案對比與選型建議
- 關鍵驗證點
問題:保護中斷與主程序共享的avg_data
在嵌入式系統中,中斷服務程序(ISR)和主程序(或任務)共享數據時,必須確保訪問的原子性和可見性。以下是針對該問題的具體修改步驟:
方法一:使用關中斷保護
此方法通過臨時禁用中斷來確保對共享變量的原子訪問,適用于所有平臺。
1. 添加關中斷宏
在頭文件中定義關中斷宏:
2. 修改數據讀取代碼
在 hal_get_data
函數中保護 avg_data
的讀取:
int hal_get_data() {ENTER_CRITICAL(); // 進入臨界區(關中斷)*val = avg_data; // 安全讀取共享數據EXIT_CRITICAL(); // 退出臨界區(開中斷)return 0;
}
3. 修改中斷服務程序(ISR)
在 module_isr
中保護 avg_data
的寫入:
irqreturn_t module_isr() {ENTER_CRITICAL();avg_data = 8888;// 安全更新 avg_dataEXIT_CRITICAL();sem_give(complete);}// ...
}
注意這個做法是有風險的,在中斷處理函數中關中斷需謹慎,可能破壞中斷上下文的狀態或影響實時性詳細分析見博客
方法二:使用原子操作(需平臺支持)
如果目標平臺支持對 u16
類型的原子訪問(如ARM Cortex-M),可使用原子操作。
1. 定義原子類型
在結構體中聲明 avg_data
為原子變量:
#include <stdatomic.h>struct siliumixi {// ..._Atomic u16 avg_data; // C11原子類型// ...
};
2. 修改數據訪問代碼
-
ISR中原子寫入:
atomic_store(&chan->avg_data, calculated_value);
-
主程序原子讀取:
*val = atomic_load(&chan->avg_data); // 原子讀取
方法三:使用RTOS同步機制(如信號量)
在RTOS環境中,可通過信號量確保數據訪問的同步。
1. 擴展通道結構體
struct siliumixi {// ...sem_t data_sem; // 新增信號量// ...
};
2. 初始化信號量
在初始化時創建信號量:
chan->data_sem = sem_create(1); // 初始值為1(二進制信號量)
}
3. 保護數據訪問
-
ISR中釋放信號量:
sem_take(chan->data_sem, 0); // 獲取信號量(非阻塞)chan->avg_data = 8888; // 更新數據aicos_sem_give(chan->data_sem); // 釋放信號量}// ... }
-
主程序獲取信號量:
if (sem_take(chan->data_sem, timeout) != 0)return -ETIMEDOUT;*val = chan->avg_data;}
方案對比與選型建議
方案 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
關中斷 | 簡單高效,無額外資源消耗 | 影響中斷響應實時性 | 低延遲、單核嵌入式系統 |
原子操作 | 代碼簡潔,無鎖競爭 | 依賴平臺原子操作支持 | 支持C11原子類型的平臺 |
RTOS信號量 | 兼容多任務環境,靈活 | 增加RTOS開銷,需處理信號量超時 | 基于RTOS的多任務系統 |
關鍵驗證點
- 原子性測試:在高低優先級任務/中斷同時訪問時,數據是否一致。
- 性能測試:關中斷時長是否影響其他中斷響應(使用示波器測量最壞關中斷時間)。
- 資源占用:信號量或原子操作是否增加內存/CPU開銷。
通過上述任一方法,可有效解決共享數據 chan->avg_data
的競爭問題