Threadx 信號量semaphore


信號量(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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章