消息队列实现原理
消息队列控制块
pcHead和pcTail:队列的头和尾指针。
pcWriteTo和pcReadFrom:队列要入队和出队指向的地址,便于操作
xTasksWaitingToSend、xTasksWaitingToReceive:和任务相关的链表,
uxMessagesWaiting:队列里还没 处理消息的个数
cRxLock\cTxLock:接受锁和发送锁,任务和中断为了防止冲突而定义.
消息队列创建
//队列实现,实际是xQueueGenericCreate函数传参传入一个队列类型queueQUEUE_TYPE
//队列的创建类型
#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) //基本类型
#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) //集合类型
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) //互斥信号量
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) //计数信号量
#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) //二制信号量
#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) //递归信号量
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )
#endif
/*
参数:
uxItemSize
uxQueueLength
ucQueueType
返回值
QueueHandle_t 队列的句柄,其实是对于列控制块地址
*/
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )
{
Queue_t *pxNewQueue;
size_t xQueueSizeInBytes;
uint8_t *pucQueueStorage;
//队列内存空间为空
if( uxItemSize == ( UBaseType_t ) 0 )
{
/* 队列字节大小赋值为0 */
xQueueSizeInBytes = ( size_t ) 0;
}
else
{
/* 队列字节大小 赋值为 长度*每个队列项的大小 */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
}
//申请内存空间 = 消息队列控制块大小+消息队列空间大小
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );
if( pxNewQueue != NULL )
{
/* 找到消息队列操作空间的首地址 */
pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t );
//初始化一个新的消息队列
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
}
return pxNewQueue;
}
/*
参数:
pucQueueStorage:队列操作空间的首地址
ucQueueType:队列类型
pxNewQueue :队列句柄
*/
static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, const uint8_t ucQueueType, Queue_t *pxNewQueue )
{
/* Remove compiler warnings about unused parameters should
configUSE_TRACE_FACILITY not be set to 1. */
( void ) ucQueueType;
if( uxItemSize == ( UBaseType_t ) 0 )
{
/* 把队列控制块首地址赋值到队列头指针上 ???? 这是互斥信号使用,后面再分析 */
pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
}
else
{
/* 把队列空间首地址赋值给队列头指针上 */
pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
}
/* 长度 单元大小 */
pxNewQueue->uxLength = uxQueueLength;
pxNewQueue->uxItemSize = uxItemSize;
//队列重置函数
( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
}
/*
参数:
xQueue 队列句柄
xNewQueue 操作队列的状态是什么,新建pdTURE还是已经创建好了
返回值:
*/
BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
{
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
//进入临界段,这个时候操作队列控制块,不允许打断
taskENTER_CRITICAL();
{
/*
1、头地址赋值
2、等待处理的消息个数为0
3、写入指针赋值为队列头指针
4、读出指针写入最后一个可用消息
5、赋值队列为解锁状态
*/
pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );
pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
pxQueue->pcWriteTo = pxQueue->pcHead;
pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
pxQueue->cRxLock = queueUNLOCKED;
pxQueue->cTxLock = queueUNLOCKED;
//判断是否为新建队列
if( xNewQueue == pdFALSE )
{
/* 判断发送等待列表里面是否有任务 */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend )