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);
}
发布了41 篇原创文章 · 获赞 2 · 访问量 3249

猜你喜欢

转载自blog.csdn.net/qq_45683435/article/details/104196728