1 前言
互斥鎖是實作傳統重入互斥體的核心對象。互斥鎖允許多個線程通過確定對資源的互斥通路來安全地共享相關的硬體或軟體資源。
我正在學習 Zephyr,一個很可能會用到很多物聯網裝置上的作業系統,如果你也感興趣,可點此檢視文章zephyr學習筆記彙總。
2 概念
可以定義任何數量的互斥鎖。 每個互斥量都由其記憶體位址引用。
互斥鎖具有以下關鍵屬性:
- 鎖定計數,訓示互斥鎖已被鎖定的線程鎖定的次數。 計數為零表示互斥鎖已解鎖。
- 一個擁有線程,用于辨別已鎖定互斥鎖的線程。
互斥量在使用之前必須初始化。這将其鎖定計數設定為零。
需要使用共享資源的線程必須首先通過鎖定關聯的互斥鎖來獲得專用權限才能通路它。 如果該互斥體已被另一個線程鎖定,則送出請求的線程可以選擇等待該互斥體被解鎖。
在鎖定互斥鎖後,線程可以安全地使用相關資源,隻要需要; 但是,盡可能縮短鎖定時間以避免對要使用該資源的其他線程産生負面影響,這是公認的較好的做法。 當線程不再需要該資源時,它必須解鎖該互斥體以允許其他線程使用該資源。
任何數量的線程可能會同時等待鎖定的互斥鎖。當互斥鎖變為解鎖時,它将被等待時間最長的最高優先級線程鎖定。
注意:互斥對象不适用于ISR。
複制
2.1 可重入鎖定
一個線程允許鎖定已經被它鎖定的互斥鎖。這使得線程可以在互斥量可能已經或可能未被鎖定的期間上通路相關資源。
一個線程重複鎖定的互斥鎖需要解鎖相同次數,才能完全解鎖,以便可以由另一個線程聲明。
2.2 優先繼承
已鎖定互斥鎖的線程有資格獲得優先級繼承。這意味着如果更高優先級的線程開始等待互斥量,核心将暫時提升線程的優先級。 這允許擁有線程完成其工作并通過以與等待線程相同的優先級執行來更快速地釋放互斥體。 一旦互斥鎖被解鎖,解鎖線程會将其優先級重置為鎖定該互斥鎖之前的級别。
CONFIG_PRIORITY_CEILING 配置選項限制了由于優先級繼承而導緻核心可以提高線程優先級的程度。 預設值0允許無限升高。
當兩個或更多線程等待由較低優先級線程保持的互斥量時,核心會在每次線程開始等待(或放棄等待)時調整擁有線程的優先級。 當最終解鎖互斥鎖時,解鎖線程的優先級正确地恢複到原來的非高優先級。
當一個線程同時持有兩個或多個互斥鎖時,核心不完全支援優先級繼承。 當所有互斥鎖被釋放時,這種情況可能導緻線程的優先級不會恢複到原來的非高優先級。 建議在不同優先級的線程之間共享多個互斥鎖時,線程隻鎖定一個互斥鎖。
3 操作
3.1 定義互斥鎖
互斥鎖是使用 struct k_mutex 類型的變量定義的。它必須通過調用 k_mutex_init() 來初始化。
以下代碼定義并初始化互斥鎖。
struct k_mutex my_mutex;
k_mutex_init(&my_mutex);
複制
或者,可以通過調用 K_MUTEX_DEFINE 在編譯時定義和初始化互斥鎖。
以下代碼與上面的代碼段具有相同的效果。
K_MUTEX_DEFINE(my_mutex);
複制
3.2 鎖定互斥鎖
通過調用 k_mutex_lock() 來鎖定互斥鎖。
以下代碼建構在上面的示例上,并且如果互斥體已被另一個線程鎖定,它将無限期地等待互斥體變為可用。
k_mutex_lock(&my_mutex, K_FOREVER);
複制
以下代碼最多等待100毫秒以使互斥鎖可用,并在互斥鎖不可用時發出警告。
if (k_mutex_lock(&my_mutex, K_MSEC(100)) == 0) {
/* mutex successfully locked */
} else {
printf("Cannot lock XYZ display\n");
}
複制
3.3 解鎖互斥鎖
通過調用 k_mutex_unlock() 解鎖互斥鎖。
以下代碼基于上面的示例建構,并解鎖先前被該線程鎖定的互斥鎖。
k_mutex_unlock(&my_mutex);
複制
4 建議用法
使用互斥鎖來提供資源(如實體裝置)的獨占通路權限。
5 配置選項
CONFIG_PRIORITY_CEILING
複制
6 APIs
下列互斥鎖API,都在 kernel.h 中提供了:
K_MUTEX_DEFINE
k_mutex_init()
k_mutex_lock()
k_mutex_unlock()
複制