在多線程/多任務系統中,資源競爭會導致數據不一致或系統死鎖,信號量(Semaphore)與互斥鎖(Mutex)通過同步機制協調共享資源的訪問,其核心原理與實現如下:
1. 互斥鎖:獨占式資源訪問
互斥鎖確保同一時刻僅一個執行單元(線程/任務)訪問資源,適用于嚴格互斥場景(如修改全局變量)。
操作流程:pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 初始化鎖
void critical_section() {
pthread_mutex_lock(&lock); // 獲取鎖(阻塞或失敗返回)
// 訪問共享資源(如寫全局變量)
pthread_mutex_unlock(&lock); // 釋放鎖
}
關鍵特性:
所有權:鎖的持有者必須負責釋放,不可跨線程解鎖。
優先級繼承:部分RTOS(如FreeRTOS)自動提升低優先級任務的優先級,避免優先級反轉。
2. 信號量:計數型資源池管理
信號量通過計數器管理資源池,允許指定數量的執行單元同時訪問資源,適用于流量控制或生產者-消費者模型。
二進制信號量(類似互斥鎖):sem_t sem;
sem_init(&sem, 0, 1); // 初始值1(可用資源數)
void access_resource() {
sem_wait(&sem); // 計數器減1(若為0則阻塞)
// 使用資源
sem_post(&sem); // 計數器加1,喚醒等待者
}
計數信號量:sem_init(&sem, 0, 5); // 允許5個線程并發訪問
3. 典型應用場景
硬件外設競爭:
多個任務訪問同一SPI總線時,使用互斥鎖確保單次獨占通信。
// FreeRTOS示例
xSemaphoreTake(spi_mutex, portMAX_DELAY); // 獲取鎖
spi_send_data(data); // 操作SPI
xSemaphoreGive(spi_mutex); // 釋放鎖
任務同步:
生產者任務生成數據后通過信號量通知消費者,實現無鎖隊列同步。
// 生產者
produce_data(buffer);
sem_post(&data_ready); // 增加信號量
// 消費者
sem_wait(&data_ready); // 等待信號量
consume_data(buffer);
4. 風險規避策略
死鎖預防:
順序加鎖:所有線程按固定順序獲取多個鎖(如先A后B)。
超時機制:設定鎖等待時間上限(如pthread_mutex_timedlock)。
資源泄漏監控:
使用靜態分析工具(如Coverity)檢測未釋放的鎖或信號量。
總結
信號量與互斥鎖通過不同策略解決資源競爭:
互斥鎖:通過強制串行化實現獨占訪問,適用于單資源嚴格互斥場景;
信號量:通過計數控制管理資源池,適用于多實例資源共享或任務同步。
開發中需遵循**“最小化臨界區”**原則,縮短鎖持有時間,避免優先級反轉與死鎖。在實時系統中,可結合優先級天花板協議(Priority Ceiling)增強確定性。未來趨勢將傾向于無鎖數據結構(如RCU)與硬件原子操作(如ARM的LDREX/STREX指令),進一步提升并發性能。