? ? ? ? 互斥鎖的所有權:
????????互斥量的狀態只有兩種,開鎖或閉鎖(兩種狀態值)。當有線程持有它時,互斥量處于閉鎖狀態,由這個線程獲得它的所有權。相反,當這個線程釋放它時,將對互斥量進行開鎖,失去它的所有權。當一個線程持有互斥量時,其他線程將不能夠對它進行開鎖或持有它,持有該互斥量的線程也能夠再次獲得這個鎖而不被掛起,這個特性與一般的二值信號量有很大的不同:在信號量中,線程遞歸持有會發生主動掛起(最終形成死鎖)。
一、為什么互斥量不能在中斷服務例程中使用?
????????首先必須明確一點,無論是在裸機還是RTOS實時操作系統,在中斷服務ISR中,都要求中斷處理快速執行,絕對不允許中斷出現任何阻塞的操作,否則會影響確保其他任務的實時運行,破壞系統的穩定性。
? ? ? ? 對于任何RTOS實時操作系統,在中斷服務ISR中,無論是對于互斥鎖 Mutex 還是 信號量 sem,絕對不允許出現任何可能阻塞中斷處理的行為和操作。
????????即:堅決不能在中斷服務ISR中,調用 take mutex 或者 take sem。因為當其他線程中一旦已經獲取 mutex 或 sem 時,當中斷 INT 打斷線程,進行中斷上下文切換時,在中斷服務ISR中,執行take mutex 或者 take sem操作,將使的整個中斷進入阻塞狀態。嚴重影響破壞整個系統的實時性和穩定性。
1.?根本原因:阻塞特性
互斥量(mutex)的核心特性是可能引發阻塞:
當互斥量已被占用時,
rt_mutex_take()
?會阻塞當前線程中斷上下文不允許阻塞(必須快速執行并退出),因為 阻塞操作會觸發線程調度
rt_schedule(),保存線程切換時的上下文到TCB
,但是 中斷上下文沒有線程控制塊TCB可被調度使用。
2.?中斷上下文限制
????????中斷服務例程 ISR 運行在中斷上下文中,在中斷中是沒有所謂的線程上下文的(例如當前線程控制塊),而互斥量的操作依賴于 Thread 線程上下文(eg:記錄持有hold互斥量的當前線程)
同時源碼中明確表示,在中斷中禁用:
3.?優先級繼承的不可行性
互斥量有優先級繼承機制:
中斷沒有"線程任務優先級"的概念,無法參與優先級繼承
中斷沒有線程控制塊 TCB(
struct rt_thread
),沒有辦法去記錄線程的優先級相關參數
總結: 為什么中斷中不可以釋放互斥鎖(mutex)和 獲取 mutex?
????????互斥鎖具有所有權概念,只有持有鎖的線程才能釋放它。中斷上下文沒有線程控制塊(即沒有線程身份),因此無法滿足互斥鎖的所有權要求。此外,互斥鎖的釋放操作可能涉及優先級繼承的解除,這需要修改持有鎖的線程的優先級,而中斷上下文無法安全地執行這些操作(因為可能涉及調度,而中斷中不能調度)。
二、線程多次持有互斥量的理解
1.?遞歸鎖特性
????????互斥量有一個特性叫做 " 遞歸鎖(Recursive Lock)",即同一個線程可以多次獲取(take)同一個互斥量,而不會造成死鎖。每次獲取互斥量后,必須對應相同次數的釋放(release)操作,互斥量才會真正被釋放給其他線程。
例如如下使用:
rt_mutex_t mutex;
void thread_function(void)
{// 第一次獲取互斥量rt_mutex_take(mutex, RT_WAITING_FOREVER);// ... 執行一些操作 ...// 第二次獲取同一個互斥量(同一個線程)rt_mutex_take(mutex, RT_WAITING_FOREVER); // 這里不會阻塞,因為已經持有該互斥量// ... 更多操作 ...// 第一次釋放互斥量(互斥量仍然被持有,因為獲取了兩次)rt_mutex_release(mutex);// 第二次釋放互斥量,此時互斥量才真正被釋放rt_mutex_release(mutex);
}
Mutex 為什么需要多次獲取?
????????這種情況通常出現在遞歸函數中,或者在一個函數中調用了另一個函數,而這兩個函數都需要操作同一個互斥量保護的數據。例如:
void function_a(void)
{rt_mutex_take(mutex, RT_WAITING_FOREVER);function_b(); // 這個函數內部也會獲取同一個互斥量rt_mutex_release(mutex);
}
void function_b(void)
{rt_mutex_take(mutex, RT_WAITING_FOREVER);// 做一些操作rt_mutex_release(mutex);
}
????????如果沒有遞歸鎖的特性,那么當線程在`function_a`中已經持有互斥量,再進入`function_b`嘗試獲取同一個互斥量時,就會發生死鎖(因為線程會等待自己釋放互斥量)。而遞歸鎖允許這種情況發生,因為同一個線程多次獲取同一個互斥量是允許的。
?2. 遞歸深度
????????RT-Thread的互斥量支持有限次數的遞歸獲取(具體次數由`RT_MUTEX_VALUE_MAX`定義,默認是0xFFFF)。超過這個次數會導致獲取失敗。
3. 釋放次數
????????必須確保 互斥鎖mutex 獲取和釋放的次數匹配,否則會導致互斥量無法被其他線程獲取,或者提前釋放導致其他線程錯誤地獲取到互斥量。