一、队列上锁
在任务级通用入队函数和中断级通用入队函数的时候都提到了队列的上锁和解锁,队列的上锁API函数为prvLockQueue()。首先来看一下队列上锁函数prvLockQueue(),此函数本质上就是一个宏,定义如下:
#define prvLockQueue( pxQueue ) \
taskENTER_CRITICAL(); \
{ \
if( ( pxQueue )->cRxLock == queueUNLOCKED ) \
{ \
( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \
} \
if( ( pxQueue )->cTxLock == queueUNLOCKED ) \
{ \
( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \
} \
} \
taskEXIT_CRITICAL()
prvLockQueue()函数很简单,就是将队列中的成员变量cRxLock和cTxLock设置为queueLOCKED_UNMODIFIED就行了。
二、队列解锁
再来看一下队列的解锁函数prvUnlockQueue(),函数如下:
static void prvUnlockQueue( Queue_t * const pxQueue )
{
/*上锁计数器(cTxLock和cRxLock)记录了在队列上锁期间,入队或出队的数量,当队列上锁以后队列项是可以加入或者移除队列的,但是对应的列表不会更新。*/
taskENTER_CRITICAL();
{
//处理cTxLock
int8_t cTxLock = pxQueue->cTxLock;
while( cTxLock > queueLOCKED_UNMODIFIED )(1)
{
//将任务从事件列表中移除
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )(2)
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )(3)
{
/*从列表中移除的任务优先级比当前任务优先级高,进行任务切换 */
vTaskMissedYield();(4)
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
break;
}
}
}
--cTxLock;(5)
}
pxQueue->cTxLock = queueUNLOCKED;(6)
}
taskEXIT_CRITICAL();
/* Do the same for the Rx lock. */
taskENTER_CRITICAL();
{
//处理cRxLock
int8_t cRxLock = pxQueue->cRxLock;
while( cRxLock > queueLOCKED_UNMODIFIED )(7)
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
vTaskMissedYield();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
--cRxLock;
}
else
{
break;
}
}
pxQueue->cRxLock = queueUNLOCKED;
}
taskEXIT_CRITICAL();
}
- (1)、判断是否有中断向队列发送了消息。如果当队列上锁的话那么向队列发送消息成功以后会将入队计数器cTxLock加一。
- (2)、判断列表xTasksWaitingToReceive是否为空,如果不为空的话就要将相应的任务从列表中移除。
- (3)、将任务从列表xTasksWaitingToReceive中移除。
- (4)、如果刚刚从列表xTasksWaitingToReceive中移除的任务优先级比当前任务的优先级高,那么就要标记需要进行任务切换。这里调用函数vTaskMissedYield(来完成此任务,函数vTaskMissedYield()只是简单的将全局变量xYieldPending设置为pdTRUE。在时钟节拍处理函数xTaskIncrementTick0中,此函数会判断xYieldPending的值,从而决定是否进行任务切换。
- (5)、每处理完一条就将cTxLock减一,直到处理完所有的。
- (6)、当处理完以后标记cTxLock为queueUNLOCKED,也就说cTxLock是没有上锁的了。
- (7)、处理完cTxLock以后接下来就要处理xRxLock了,处理过程和xTxLock很类似。