freertos 创建互斥量_浅析FreeRTOS_v4.5.0队列、信号和Mutex互斥量共用函数体Queue.c文件...

本文详细分析了FreeRTOS_v4.5.0版本中队列、信号和Mutex互斥量共用的函数体Queue.c文件。内容涉及xQueueGenericSend和xQueueGenericReceive函数,讲解了如何在任务调度器锁定和队列锁定状态下进行数据发送和接收,并处理了可能的中断和优先级翻转情况。同时,文中提到了在队列满或空时的任务等待和超时处理策略。
摘要由CSDN通过智能技术生成

浅析FreeRTOS_v4.5.0队列、信号和Mutex互斥量共用函数体Queue.c文件

文章来源:http://gliethttp.cublog.cn[转载请声明出处]

//-----------------------------------------------------------------------------------

signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )

{

signed portBASE_TYPE xReturn = pdPASS;

xTimeOutType xTimeOut;

//2007-09-30 gliethttp

//锁住调度器,不发生线程切换

vTaskSuspendAll();

vTaskSetTimeOutState( &xTimeOut );

//2007-09-30 gliethttp

//锁住队列,不让ISR对睡眠在list队列上的task进行唤醒操作,但是可以对队列数据进行操作

//要保证对这些全局量的修改地方具有唯一性,否则两个地方都去修改同一个变量,

//那么会出现数据混乱

prvLockQueue( pxQueue );

do

{

if( prvIsQueueFull( pxQueue ) )

{

if( xTicksToWait > ( portTickType ) 0 )

{

//2007-09-30 gliethttp

//正如上边提到的,当这里正要执行的时候,ISR突然到达,那么

//ISR可能把数据读出去了,所以空出了数据,但是这里还会进行队列调整

//因为ISR中发现Q已经被锁,所以Q不会在ISR中发生调度,仅仅是把数据读出去而已

//下面耗费多长时间也无所谓了,因为现在ISR硬件中断系统并没有关闭

vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );

taskENTER_CRITICAL();

{

//2007-09-30 gliethttp

//如果上面的ISR中断发生,那么本task已经被放到了Event事件双向链表上,

//下面的Unlock将使等待在Event事件队列双向链表上的最应该执行的task

//从事件队列双向链表上摘下,因为当下内核调度器被锁,所以恢复的task将被

//暂时放到PendingReady队列上

prvUnlockQueue( pxQueue );

if( !xTaskResumeAll() )

{

taskYIELD();

}

//2007-09-30 gliethttp

//可能确实task已经被Event事件唤醒,并且被置入了就绪运行队列,但是因为

//和他同优先级的其他task的原因,自己还没有获得cpu,而就在快要轮转到自己持有

//cpu的时候,一个高优先级的task可能又把Q填满了,

//之后本task被轮转到,获得了cpu,进而执行下面的语句

if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )

{

xReturn = errQUEUE_FULL;

}

vTaskSuspendAll();

//因为加入了lock,所以ISR中的程序不会进行Q队列操作

prvLockQueue( pxQueue );

}

taskEXIT_CRITICAL();

}

}

// 1.因为Q已经被锁住,所以在ISR中不会处理等待在Q队列上的task,但是会对Q上的数据进行操作

// 2.调度器已经上锁,不会发生调度,本task肯定会继续执行下面的代码

if( xReturn != errQUEUE_FULL )

{

taskENTER_CRITICAL();

{

//可能发生的ISR,又把Q填满了

if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )

{

prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );

xReturn = pdPASS;

++( pxQueue->xTxLock );

}

else

{

xReturn = errQUEUE_FULL;

}

}

taskEXIT_CRITICAL();

}

if( xReturn == errQUEUE_FULL )

{

if( xTicksToWait > 0 )

{

//2007-09-30 gliethttp

// 1.确实因为Recve事件唤醒了本task,但是在执行上面的非原子操作的过程中,

// if( xReturn != errQUEUE_FULL )的汇编代码之间,可能ISR又将Q填满了

// 如果是这样,那么TimeOut一定还没有到达,所以需要继续在时间链表上挂起自己,继续等待

if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )

{

xReturn = queueERRONEOUS_UNBLOCK;

}

}

}

}

while( xReturn == queueERRONEOUS_UNBLOCK );

prvUnlockQueue( pxQueue );

xTaskResumeAll();

return xReturn;

}

//-----------------------------------------------------------------------------------

signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )

{

signed portBASE_TYPE xReturn = pdTRUE;

xTimeOutType xTimeOut;

signed portCHAR *pcOriginalReadPosition;

vTaskSuspendAll();

vTaskSetTimeOutState( &xTimeOut );

prvLockQueue( pxQueue );

do

{

if( prvIsQueueEmpty( pxQueue ) )

{

if( xTicksToWait > ( portTickType ) 0 )

{

#if ( configUSE_MUTEXES == 1 )

{

if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )

{

//2007-09-28 gliethttp

//优先级继承

//如果将要悬挂在该Q上的本task对应的优先级高于Q队列上正在持有Q使用权的pxMutexHolder对应的task的优先级

//,那么提升正在使用Q资源的pxMutexHolder对应的task的优先级到达本task的优先级

//2007-09-29 gliethttp

//低于持有mutex互斥量的task优先级的task-C不会抢占C

//高于task-C优先级的task应该抢占C

//比悬停在Q上的最高优先级task-A的优先级低的同时比持有mutex互斥量的C优先级高的task们

//才会出现优先级翻转现象

//[注:对于优先级翻转问题,可以参看《浅析μCOS/II v2.85内核OSMboxPend()和OSMboxPost()函数工作原理》

// 和《关于uC/OS-II中优先级翻转问题(转)》.文章地址:http://gliethttp.cublog.cn

//]

portENTER_CRITICAL();

vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );

portEXIT_CRITICAL();

}

}

#endif

vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );

taskENTER_CRITICAL();

{

prvUnlockQueue( pxQueue );

if( !xTaskResumeAll() )

{

taskYIELD();

}

//2007-09-29 gliethttp

//可能确实task已经被Event事件唤醒,并且被置入了就绪运行队列,但是因为

//和他同优先级的其他task的原因,自己还没有获得cpu,而就在快要轮转到自己持有

//cpu的时候,一个高优先级的task可能把Q中数据给读走了,所以Q又空了,

//之后本task被轮转到,获得了cpu,进而执行下面的语句

if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )

{

xReturn = errQUEUE_EMPTY;

}

vTaskSuspendAll();

prvLockQueue( pxQueue );

}

taskEXIT_CRITICAL();

}

}

if( xReturn != errQUEUE_EMPTY )

{

taskENTER_CRITICAL();

{

if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )

{

pcOriginalReadPosition = pxQueue->pcReadFrom;

prvCopyDataFromQueue( pxQueue, pvBuffer );

//2007-09-29

//xJustPeeking=true表示仅仅偷偷的数据读出来,就像小偷一样,它还会花费

//下面的功夫来恢复现场

if( xJustPeeking == pdFALSE )

{

--( pxQueue->uxMessagesWaiting );

++( pxQueue->xRxLock );

#if ( configUSE_MUTEXES == 1 )

{

if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )

{

//2007-09-29 gliethttp

//mutex_lock();mutex_unlock()会比较清晰一些,当Q用作mutex功能时,就不是Q了,就像

//------------------------------------------------------

//vSemaphoreCreateBinary

//xSemaphoreTake

//xSemaphoreGive

//xSemaphoreGiveFromISR

//xSemaphoreCreateMutex

//就像Semaphore函数一样,可以给他们取个名字为

//xMutexCreatexxxxxxxxx

//xMutexTake

//xMutexGive

//xMutexGiveFromISR

//xMutexCreate

//------------------------------------------------------

//但是实际上Mutex功能是为Semaphore信号量提供的防止信号量保护的内容出现优先级翻转

//的基于优先级继承的互斥机制

//其中xQueueReceive等效于mutex_lock();

// xQueueSend 等效于mutex_unlock();

//pxMutexHolder对应的是正在使用本Q队列的task上下文句柄

//如果某一个时刻因为,优先级高于本task的另一个task被阻塞在这个Q上的时候

//那么当前拥有该Q运行权利的本task的优先级将会被提升到被阻塞的task对应的优先级

//2007-09-29 gliethttp

//低于持有mutex互斥量的task优先级的task-C不会抢占C

//高于task-C优先级的task应该抢占C

//比悬停在Q上的最高优先级task-A的优先级低的同时比持有mutex互斥量的C优先级高的task们

//才会出现优先级翻转现象

//本task持有互斥锁

pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();

}

}

#endif

}

else

{

//2007-09-29 gliethttp

//如果不是从Q上读取数据,那么这次唤醒的等待在Q上的task等于没有唤醒,

//所以下面++( pxQueue->xTxLock ),再去唤醒一个等待在Q上的task

pxQueue->pcReadFrom = pcOriginalReadPosition;

++( pxQueue->xTxLock );

}

xReturn = pdPASS;

}

else

{

xReturn = errQUEUE_EMPTY;

}

}

taskEXIT_CRITICAL();

}

if( xReturn == errQUEUE_EMPTY )

{

if( xTicksToWait > 0 )

{

if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )

{

xReturn = queueERRONEOUS_UNBLOCK;

}

}

}

} while( xReturn == queueERRONEOUS_UNBLOCK );

prvUnlockQueue( pxQueue );

xTaskResumeAll();

return xReturn;

}

//-----------------------------------------------------------------------------------

static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )

{

if( pxQueue->uxItemSize == 0 )

{

#if ( configUSE_MUTEXES == 1 )

{

if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )

{

//2007-09-28 gliethttp

//说是恢复Q上task的优先级,倒不如说调用了mutex_unlock()

//其中xQueueReceive等效于mutex_lock();

// xQueueSend 等效于mutex_unlock();

//所以对于mutex,就没有什么Q的概念了

//任何一个对mutex发送的数据,即:xQueueSend,都会使mutex解锁,因为

//下一次肯定是等待在Q-mutex上最高优先级的task获得执行

//2007-09-29 gliethttp

//低于持有mutex互斥量的task优先级的task-C不会抢占C

//高于task-C优先级的task应该抢占C

//比悬停在Q上的最高优先级task-A的优先级低的同时比持有mutex互斥量的C优先级高的task们

//才会出现优先级翻转现象

vTaskPriorityDisinherit( ( void * const ) pxQueue->pxMutexHolder );

}

}

#endif

}

else if( xPosition == queueSEND_TO_BACK )

{

memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );

pxQueue->pcWriteTo += pxQueue->uxItemSize;

if( pxQueue->pcWriteTo >= pxQueue->pcTail )

{

pxQueue->pcWriteTo = pxQueue->pcHead;

}

}

else

{

memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );

pxQueue->pcReadFrom -= pxQueue->uxItemSize;

if( pxQueue->pcReadFrom < pxQueue->pcHead )

{

pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );

}

}

++( pxQueue->uxMessagesWaiting );

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值