FreeRTOS互斥量和递归互斥量笔记(自用)

跟二值信号量一样,互斥量和递归互斥量都是队列长度为1消息项大小为0的消息队列,但是互斥量拥有优先级继承的机制,这能有效的防止优先级翻转的现象。假如有三个任务,优先级分别为高,中,低。在高任务获取互斥量时,互斥量已经被低任务获取了,高任务因此被阻塞这时中任务就绪了所有低任务吧系统给力中任务,这就导致了高任务等待中任务运行后才能获取到系统,这就造成了优先级的翻转。FreeRTOS为了防止这一现象,引入了优先级继承的机制,当高优先级任务获取互斥量时,互斥量被低优先级任务拥有那么低优先级任务的优先级会暂时被提高至高优先级。

要实现这一机制任务控制块增加了两个成员变量。其句柄结构体也为xSemaphoreHandle,其本质为QueueHandle_t (void *)

UBaseType_t		uxBasePriority;		/* 任务分配的优先级,优先级继承时使用(记录初始优先级) */
UBaseType_t		uxMutexesHeld;      /* 记录任务所持有的互斥量数量 */

目录

xSemaphoreCreateMutex互斥量创建函数


xSemaphoreCreateMutex互斥量创建函数

#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )

//类型参数必须开启系统追踪等功能时才有效
QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
{
	Queue_t *pxNewQueue;
	const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0;
    //创建一个队列长度为1,项大小为0的队列
	pxNewQueue=( Queue_t* )xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType );
	prvInitialiseMutex( pxNewQueue );//初始化互斥量
	return pxNewQueue;
}

prvInitialiseMutex互斥量初始化函数


为了代码一致性和可阅读性在queue.c中宏定义了
#define pxMutexHolder					pcTail
#define uxQueueType						pcHead
#define queueQUEUE_IS_MUTEX				NULL

static void prvInitialiseMutex( Queue_t *pxNewQueue )
{
	if( pxNewQueue != NULL )
	{
		pxNewQueue->pxMutexHolder = NULL;//此变量记录当前拥有改互斥量的任务控制块
		pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;
		/* 递归互斥量使用的,记录任务重复获取的次数 */
		pxNewQueue->u.uxRecursiveCallCount = 0;
	    /* 发送消息给队列(互斥量初始值为1)*/
		( void )xQueueGenericSend(pxNewQueue, NULL,( TickType_t )0U,queueSEND_TO_BACK );
	}
}

xSemaphoreCreateRecursiveMutex递归互斥量创建函数

其代码与互斥量一样只是类型参数不同

#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )

互斥量和递归互斥量获取函数

他们本质上都是xQueueGenericReceive队列消息读取,只是递归有对其封装了一些逻辑判断。

队列函数解析看消息队列

xSemaphoreTake互斥量获取函数

#define xSemaphoreTake( xSemaphore, xBlockTime )		\
xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )


//xQueueGenericReceive在这些地方增加了
if( uxMessagesWaiting > ( UBaseType_t ) 0 )//互斥量可获取(消息队列中有消息)
{
    。。。。
    if( xJustPeeking == pdFALSE )
    {
        。。。。
        #if ( configUSE_MUTEXES == 1 )
		{
			if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
			{
				//pvTaskIncrementMutexHeldCount函数uxMutexesHeld加一返回任务控制块
                pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); 
			}
		}
		#endif /* configUSE_MUTEXES */
        。。。。。
    }
        。。。。。
}
。。。。。

//在互斥量无法获取时,检测是否超时
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
    ....
    if( prvIsQueueEmpty( pxQueue ) != pdFALSE )//在一次检测队列是否为空(互斥量是否可获取)
	{
        #if ( configUSE_MUTEXES == 1 )
		{
			if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
			{
				taskENTER_CRITICAL();
				{
					//优先级继承,当前pxQueue->pxMutexHolder指向拥有此互斥量的任务控制块
                    vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
				}
				taskEXIT_CRITICAL();
			}
		}
		#endif
        。。。。
    }
}

pvTaskIncrementMutexHeldCount函数 
void *pvTaskIncrementMutexHeldCount( void )
	{
		if( pxCurrentTCB != NULL )
		{
			( pxCurrentTCB->uxMutexesHeld )++;
		}
		return pxCurrentTCB;
	}
vTaskPriorityInherit函数
void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
{
    TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
    if( pxMutexHolder != NULL )//某些情况下此值可能为0,如在中断中释放了互斥量
    {
        if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )//当前拥有互斥量的任务优先级低于当前的任务
        {
            if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
            {
                //记录一下,这个不是很重要
                listSET_LIST_ITEM_VALUE( 
                    &( pxTCB->xEventListItem ), 
                    ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); 
            }
            //检测当前拥有互斥量的任务是否在就绪列表中
            if( 
                listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), 
                &( pxTCB->xStateListItem ) ) != pdFALSE 
            )在
			{
                // 将当前拥有互斥量的任务从函数中删除
                if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
                {
                    //更新uxTopReadyPriority的值
                    taskRESET_READY_PRIORITY( pxTCB->uxPriority );
                }
                pxTCB->uxPriority = pxCurrentTCB->uxPriority;//优先级继承
				prvAddTaskToReadyList( pxTCB );             //加入高优先级的就绪列表
            }
            else//不在就绪列表中,直接进行优先级继承
            {
                pxTCB->uxPriority = pxCurrentTCB->uxPriority;
            }
        }
    }
}

xSemaphoreTakeRecursive递归互斥量获取函数

#define xSemaphoreTakeRecursive( xMutex, xBlockTime )	\
xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )

/*********
xMutex:互斥量句柄
xTicksToWait:最大阻塞时间
**********/
BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait )
{
    BaseType_t xReturn;
	Queue_t * const pxMutex = ( Queue_t * ) xMutex;
    //xTaskGetCurrentTaskHandle函数获取当前任务控制块,
    if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() )//当前任务拥有此递归互斥量并再次获取。 
    {
        ( pxMutex->u.uxRecursiveCallCount )++;//记录获取互斥量的次数
        xReturn = pdPASS;
    }
    else    //第一次获取
    {
        xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE );//获取互斥量
        if( xReturn != pdFAIL )
        {
            ( pxMutex->u.uxRecursiveCallCount )++;//记录获取互斥量的次数
        }
    }
    return xReturn;
}

互斥量和递归互斥量释放函数

xSemaphoreGive互斥量释放函数

函数也是调用的发送队列消息函数。

#define xSemaphoreGive( xSemaphore )		\
xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )

xQueueGenericSend函数在互斥量开启后并没有增加一些代码但其中中调用的prvCopyDataToQueue函数添加了一些代码

static BaseType_t prvCopyDataToQueue
( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
{
    BaseType_t xReturn = pdFALSE;
    UBaseType_t uxMessagesWaiting;

    uxMessagesWaiting = pxQueue->uxMessagesWaiting;//赋值队列当前长度
    
    if( pxQueue->uxItemSize == ( UBaseType_t ) 0 )//项大小为0,信号量,互斥量都是项大小为0
    {
        #if ( configUSE_MUTEXES == 1 )
        if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )//互斥量
        {
            //取消优先级继承
            xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );
            pxQueue->pxMutexHolder = NULL;
        }
        #endif
    }
    else if(xPosition == queueSEND_TO_BACK)
    {
        ...
    }
    else
    {
        .....
    }
    pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;
}
xTaskPriorityDisinherit取消优先级继承函数
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
{
    TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;//pxTCB指向拥有互斥量的任务
	BaseType_t xReturn = pdFALSE;
    if( pxMutexHolder != NULL )
    {
        if( pxTCB->uxPriority != pxTCB->uxBasePriority )//互斥量当前优先级大于任务原先的优先级,代表有优先级继承
        {
            ( pxTCB->uxMutexesHeld )--;//uxMutexesHeld-1
            //uxMutexesHeld记录的是拥有的互斥量的数量
            if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )
            {
                //将任务从高优先级的列表中退出
                if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
                {
                    //更新uxTopReadyPriority
                    taskRESET_READY_PRIORITY( pxTCB->uxPriority );
                }
                pxTCB->uxPriority = pxTCB->uxBasePriority;恢复任务原先的优先级
                //更新xItemValue,不重要
                listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority );
                prvAddTaskToReadyList( pxTCB );//任务重新加入自己原先的就绪列表
                xReturn = pdTRUE;
            }
        }
    }
    return xReturn;
}

xSemaphoreGiveRecursive递归互斥量释放函数

#define xSemaphoreGiveRecursive( xMutex )	xQueueGiveMutexRecursive( ( xMutex ) )

BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
{
    BaseType_t xReturn;
	Queue_t * const pxMutex = ( Queue_t * ) xMutex;

    if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() )//当前任务是拥有此递归互斥量的任务
    {
        ( pxMutex->u.uxRecursiveCallCount )--;
        
        if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 )
        {
            //释放递归互斥量
            ( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
        }
        xReturn = pdPASS;
    }
    else
    {
        xReturn = pdFAIL;
    }
    return xReturn;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值