1. 程式人生 > >UCOS學習筆記(六)訊號量

UCOS學習筆記(六)訊號量

前言

這是用markdown寫的第一篇部落格,如果寫的不好見諒啦

訊號量

基本概念及一些注意事項

將訊號量用於同步的概念是荷蘭的電腦科學家Edgser Dijkstra 在1959 年發明的。在電腦軟體中,訊號量是一種用於多工排程的協議機制。 訊號量像是一種上鎖機制,程式碼必須獲得相應的鑰匙才能繼續執行,一旦獲得了鑰匙就意味著該任務具有了進入被鎖部分程式碼的許可權。 訊號量用於控制對共享資源的保護,但是現在基本用來做任務同步用 對共享資源保護的方法:關中斷、對任務排程器加鎖、使用訊號量加鎖、mutex方式 注意:一般不使用關中斷的方式,除非任務十分簡短,因為關中斷是關閉所有的中斷,包含滴答定時器中斷,會使系統時鐘出現問題

一般有倆種類型的訊號量:二值訊號量和多值訊號量。二值訊號量的值只能是0和1,多值訊號量的值可以通過更改OS_SEM_CTR的定義修改為8、16、32位。 只有任務才允許使用訊號量,ISR是不允許的。 訊號量是核心物件,通過資料型別OS_SEM定義,應用中可以有任意多個訊號量。 等待訊號量 Pend 傳送或釋放訊號量 Post 二進位制訊號量用於那些一次只能有一個任務使用的資源,比如IO裝置 多值訊號量用於某些資源可以被幾個任務來使用

資料型別

struct  os_sem {                                            /* Semaphore                                              */
/* ------------------ GENERIC MEMBERS ------------------ */ OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_SEM */ CPU_CHAR *NamePtr; /* Pointer to Semaphore Name (NUL terminated ASCII) */
OS_PEND_LIST PendList; /* List of tasks waiting on semaphore */ #if OS_CFG_DBG_EN > 0u OS_SEM *DbgPrevPtr; OS_SEM *DbgNextPtr; CPU_CHAR *DbgNamePtr; #endif /* ------------------ SPECIFIC MEMBERS ------------------ */ OS_SEM_CTR Ctr; CPU_TS TS; };

其中中間與除錯有關的部分暫時不管 第一個為“Type”域,表明這定義的是一個訊號量(UCOSIII每個核心物件都有Type域) 第二個為訊號量的名字(UCOSIII每個核心物件都可以被賦予一個名字,為ASCII字串組成,但必須以空字元結尾) 第三個為掛起佇列若有多個任務等待訊號量,訊號量就會將這些任務放入其掛起佇列中 OS_SEM_CTR為訊號量中包含的一個訊號量計數變值(若為1該訊號量為二值訊號量,若不為1該訊號量為多值訊號量) 最後一個是系統時間戳。

相關API函式

函式名 作用
OSSemCreat() 建立一個訊號量
OSSemDel 刪除一個訊號量
OSSemPend() 等待一個訊號量
OSSemPendAbrot() 取消等待
OSSemPost() 釋放或者發出一個訊號量
OSSemSet() 強制設定一個訊號量

其中重點標註的三個API便是常用的三個,不僅僅是訊號量,內建訊號量、互斥訊號量(Mutex)、內建互斥訊號量訊息佇列也是一般只是用Create、Pend、Post三個函式。

注意事項

用訊號量訪問共享資源不會導致中斷延遲。當任務在執行訊號量所保護的共享資源時,ISR 或高優先順序任務可以搶佔該任務。 應用中可以有任意個訊號量用於保護共享資源。然而,推薦將訊號量用於I/O 埠的保護,而不是記憶體地址。 訊號量經常被過度使用。很多情況下,訪問一個簡短的共享資源時不推薦使用訊號量,請求和釋放訊號量會消耗CPU 時間。通過關/開中斷能更有效地執行這些操作。為了說明,假設兩個任務共享一個32 位的整數變數。第一個任務將這個整數變數加1,第二個任務將這個變數清零。考慮到執行這些操作用時很短,不需要使用訊號量。執行這個操作前任務只需關中斷,執行完畢後再開中斷。若操作浮點數變數且處理器不支援硬體浮點操作時,就需要用到訊號量。因為在這種情況下處理浮點數變數需較長時間。 訊號量會導致一種嚴重的問題:優先順序反轉。 對於如何處理優先順序翻轉就需要使用互斥訊號量