前言
這是用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,第二個任務将這個變量清零。考慮到執行這些操作用時很短,不需要使用信号量。執行這個操作前任務隻需關中斷,執行完畢後再開中斷。若操作浮點數變量且處理器不支援硬體浮點操作時,就需要用到信号量。因為在這種情況下處理浮點數變量需較長時間。
信号量會導緻一種嚴重的問題:優先級反轉。
對于如何處理優先級翻轉就需要使用互斥信号量了