信號量(semaphore)用來保護共享資源,臨界區訪問,同步;可以用於生產者-消費者模式中提供事件通知。
如果信號量計數器最大爲1,其值可能爲0或1,成爲二進制信號量。二進制信號量作用類似互斥量,但信號量不支持所有權,不支持優先級繼承。
信號量控制塊
Threadx中信號量控制塊(SCB)用來保持運行時(run-time)信號量狀態的數據結構。
/* Define the semaphore structure utilized by the application. */
typedef struct TX_SEMAPHORE_STRUCT
{
/* Define the semaphore ID used for error checking. */
ULONG tx_semaphore_id;
/* Define the semaphore's name. */
CHAR_PTR tx_semaphore_name;
/* Define the actual semaphore count. A zero means that no semaphore
instance is available. */
ULONG tx_semaphore_count;
/* Define the semaphore suspension list head along with a count of
how many threads are suspended. */
struct TX_THREAD_STRUCT *tx_semaphore_suspension_list;
ULONG tx_semaphore_suspended_count;
/* Define the created list next and previous pointers. */
struct TX_SEMAPHORE_STRUCT
*tx_semaphore_created_next,
*tx_semaphore_created_previous;
TX_THREAD *sema_last_owner;
} TX_SEMAPHORE;
域 | 意義 |
---|---|
tx_semaphore_id | 信號量ID |
tx_semaphore_name | 信號量名字指針 |
tx_semaphore_count | 信號量計數器 |
tx_semaphore_suspension_list | 信號量掛起隊列 |
tx_semaphore_suspended_count | 信號量掛起隊列中元素個數 |
tx_semaphore_created_next | 指向下一個信號量指針 |
tx_semaphore_created_previous | 指向前一個信號量指針 |
sema_last_owner | 最後一個獲取信號量線程指針 |
信號量隊列
系統中所有信號量控制塊掛載一個雙向鏈表_tx_semaphore_created_ptr中,tx_semaphore_created_next 指向下一個信號量指針,tx_semaphore_created_previous指向前一個信號量指針。
信號量API
函數 | 描述 |
---|---|
_tx_semaphore_create | 創建信號量 |
_tx_semaphore_delete | 刪除信號量 |
_tx_semaphore_get | 申請信號量 |
_tx_semaphore_info_get | 獲取信號量信息 |
_tx_semaphore_prioritize | 調整信號量掛起隊列,使優先級最高線程在最前面 |
_tx_semaphore_put | 釋放信號量 |
優先級翻轉
優先級翻轉是指較低優先級已經獲得信號量,這時較高優先級線程也需要獲得的這個信號量時,較高優先級線程會被掛起,等待信號量釋放。如果這時中等優先級任務搶佔了低優先級任務,就出現了低優先級任務先執行,高優先級任務在等待,而且時間也變得不確定。
解決信號量導致的優先級翻轉方法:開發人員通過合理設置優先級避免優先級翻轉,或暫時提高擁有信號量的線程優先級避免優先級翻轉。
互斥量支持優先級繼承功能來提高擁有信號量的線程優先級。
信號量不支持優先級繼承功能來提高擁有信號量的線程優先級。
信號量創建_tx_semaphore_create
_tx_semaphore_create用來創建信號量,入參爲信號量指針,信號量名字指針,信號量計數器初值。
UINT _tx_semaphore_create(TX_SEMAPHORE *semaphore_ptr,
CHAR *name_ptr, ULONG initial_count)
{
TX_INTERRUPT_SAVE_AREA
TX_SEMAPHORE *tail_ptr; /* Working semaphore pointer */
/* Setup the basic semaphore fields. */
#def 設置初始化值
semaphore_ptr -> tx_semaphore_name = name_ptr;
semaphore_ptr -> tx_semaphore_count = initial_count;
semaphore_ptr -> tx_semaphore_suspension_list = TX_NULL;
semaphore_ptr -> tx_semaphore_suspended_count = 0;
/* Disable interrupts to place the semaphore on the created list. */
TX_DISABLE
/* Setup the semaphore ID to make it valid. */
semaphore_ptr -> tx_semaphore_id = TX_SEMAPHORE_ID;
/* Place the semaphore on the list of created semaphores. First,
check for an empty list. */
#def 插入_tx_semaphore_created_ptr list尾部
if (_tx_semaphore_created_ptr)
{
/* Pickup tail pointer. */
tail_ptr = _tx_semaphore_created_ptr -> tx_semaphore_created_previous;
/* Place the new semaphore in the list. */
_tx_semaphore_created_ptr -> tx_semaphore_created_previous = semaphore_ptr;
tail_ptr -> tx_semaphore_created_next = semaphore_ptr;
/* Setup this semaphore's next and previous created links. */
semaphore_ptr -> tx_semaphore_created_previous = tail_ptr;
semaphore_ptr -> tx_semaphore_created_next = _tx_semaphore_created_ptr;
}
else
{
/* The created semaphore list is empty. Add semaphore to empty list. */
_tx_semaphore_created_ptr = semaphore_ptr;
semaphore_ptr -> tx_semaphore_created_next = semaphore_ptr;
semaphore_ptr -> tx_semaphore_created_previous = semaphore_ptr;
}
/* Increment the number of semaphores created counter. */
_tx_semaphore_created_count++;
/* Restore interrupts. */
TX_RESTORE
/* Return TX_SUCCESS. */
return (TX_SUCCESS);
}
刪除信號量_tx_semaphore_delete
刪除信號量,如果tx_semaphore_suspension_list掛起隊列中有線程,需要恢復線程
UINT _tx_semaphore_delete(TX_SEMAPHORE *semaphore_ptr)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *thread_ptr; /* Working thread pointer */
/* Disable interrupts to remove the semaphore from the created list. */
TX_DISABLE
/* Decrement the number of semaphores created. */
_tx_semaphore_created_count--;
/* Clear the semaphore ID to make it invalid. */
semaphore_ptr -> tx_semaphore_id = 0;
#def 從_tx_semaphore_created_ptr 隊列移除信號量
/* See if the semaphore is the only one on the list. */
if (semaphore_ptr == semaphore_ptr -> tx_semaphore_created_next)
{
/* Only created semaphore, just set the created list to NULL. */
_tx_semaphore_created_ptr = TX_NULL;
}
else
{
/* Link-up the neighbors. */
(semaphore_ptr -> tx_semaphore_created_next) -> tx_semaphore_created_previous =
semaphore_ptr -> tx_semaphore_created_previous;
(semaphore_ptr -> tx_semaphore_created_previous) -> tx_semaphore_created_next =
semaphore_ptr -> tx_semaphore_created_next;
/* See if we have to update the created list head pointer. */
if (_tx_semaphore_created_ptr == semaphore_ptr)
/* Yes, move the head pointer to the next link. */
_tx_semaphore_created_ptr = semaphore_ptr -> tx_semaphore_created_next;
}
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Walk through the semaphore list to resume any and all threads suspended
on this semaphore. */
#def 刪除tx_semaphore_suspension_list中所有線程,相應數據結構信息,並恢復線程
thread_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
while (semaphore_ptr -> tx_semaphore_suspended_count)
{
/* Lockout interrupts. */
TX_DISABLE
/* Clear the cleanup pointer, this prevents the timeout from doing
anything. */
thread_ptr -> tx_suspend_cleanup = TX_NULL;
/* Temporarily disable preemption again. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
#def 去激活定時器
/* Yes, deactivate the thread's timer just in case. */
_tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));
/* Set the return status in the thread to TX_DELETED. */
thread_ptr -> tx_suspend_status = TX_DELETED;
/* Move the thread pointer ahead. */
thread_ptr = thread_ptr -> tx_suspended_next;
#def 恢復線程
/* Resume the thread. */
_tx_thread_resume(thread_ptr -> tx_suspended_previous);
/* Decrease the suspended count. */
semaphore_ptr -> tx_semaphore_suspended_count--;
}
/* Disable interrupts. */
TX_DISABLE
/* Release previous preempt disable. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
#def 開中斷(可以搶佔了),有可能更高級線程需要執行,例如_tx_thread_resume會恢復高優先級線程,這裏進行調度
/* Check for preemption. */
if (_tx_thread_current_ptr != _tx_thread_execute_ptr)
/* Transfer control to system. */
_tx_thread_system_return();
/* Return TX_SUCCESS. */
return (TX_SUCCESS);
}