[FreeRTOS 内部实现] 互斥访问与回环队列


基础知识

[FreeRTOS 基础知识] 互斥访问与回环队列 概念


队列结构体

typedef struct QueueDefinition
{
    int8_t *pcHead;                    /*< Points to the beginning of the queue storage area. */
    int8_t *pcTail;            /*< Points to the byte at the end of the queue storage area.  Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
    int8_t *pcWriteTo;            /*< Points to the free next place in the storage area. */

    
     union                /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */
    {
        int8_t *pcReadFrom;        /*< Points to the last place that a queued item was read from when the structure is used as a queue. */
        UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */
    } u;

    List_t xTasksWaitingToSend;        /*< List of tasks that are blocked waiting to post onto this queue.  Stored in priority order. */
    List_t xTasksWaitingToReceive;        /*< List of tasks that are blocked waiting to read from this queue.  Stored in priority order. */

    
     volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */
             UBaseType_t uxLength;        /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
         UBaseType_t uxItemSize;        /*< The size of each items that the queue will hold. */

    volatile int8_t cRxLock;        /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
    volatile int8_t cTxLock;        /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */

    #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
    uint8_t ucStaticallyAllocated;    /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */
    #endif

    #if ( configUSE_QUEUE_SETS == 1 )
    struct QueueDefinition *pxQueueSetContainer;
    #endif

    #if ( configUSE_TRACE_FACILITY == 1 )
    UBaseType_t uxQueueNumber;
    uint8_t ucQueueType;
    #endif
} xQUEUE;

在结构体中主要成员介绍:
List_t xTasksWaitingToSend; 等待发布到此队列的阻塞任务列表。按优先级顺序存储。
List_t xTasksWaitingToReceive; 阻塞等待从此队列读取的任务列表。按优先级顺序存储。
int8_t *pcWriteTo; 指向存储区的下一个空闲位置。
int8_t *pcReadFrom; 指向将该结构用作队列时最后从其中读取队列项的位置。


创建队列 xQueueCreate 解析

xQueueCreate( uxQueueLength, uxItemSize )
    -> xQueueGenericCreate
        -> xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); 
        -> pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );

uxQueueLength 指 队列长度
uxItemSize 指 每段长度的大小
总长度 = uxQueueLength * uxItemSize + Queue_t结构体大小

在内存中分配如下
在这里插入图片描述


队列读数据 xQueueReceive 解析

BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
->
    for( ;; )
    {
        taskENTER_CRITICAL();            // 关中断 portDISABLE_INTERRUPTS();
        {
            const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;        // 当前队列中值的总数量

            
            if( uxMessagesWaiting > ( UBaseType_t ) 0 )            // 队列中有数值
            {                            
                prvCopyDataFromQueue( pxQueue, pvBuffer );        // 将队列中pcReadFrom指向的值取出放到pvBuffer中,pcReadFrom指向下一个位置
                traceQUEUE_RECEIVE( pxQueue );
                pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;    // 当前队列中值的总数量 -1

  
                if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )    // xTasksWaitingToSend链表中有没等待要写的任务
                {
                    if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )    // 1、将要写的任务从xTasksWaitingToSend移除;2、将要写的任务从DelayList移动到ReadyList
                    {
                        queueYIELD_IF_USING_PREEMPTION();    // 当前任务让出CPU
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();            
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                taskEXIT_CRITICAL();            // 打开中断
                return pdPASS;                   // 返回成功
            }
            else
            {
                if( xTicksToWait == ( TickType_t ) 0 )
                {
                    // 队列是空的,没有指定阻塞时间(或者阻塞时间已经过期),所以现在离开。
                    taskEXIT_CRITICAL();         // 打开中断
                    traceQUEUE_RECEIVE_FAILED( pxQueue );
                    return errQUEUE_EMPTY;        // 返回队列为空
                }
                else if( xEntryTimeSet == pdFALSE )
                {
                    // 队列为空,阻塞时间被指定,所以配置超时结构。        
                    vTaskInternalSetTimeOutState( &xTimeOut );
                    xEntryTimeSet = pdTRUE;
                }
                else
                {
                /* Entry time was already set. */
                mtCOVERAGE_TEST_MARKER();
                }
            }
        }
        taskEXIT_CRITICAL();
        
        vTaskSuspendAll();
        prvLockQueue( pxQueue );


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

            if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
            {
                traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
                // 1、当前的任务加入到队列的xTasksWaitingToReceive链表中;
                // 2、当前的任务从ReadyList移动到DelayList
                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
                prvUnlockQueue( pxQueue );
                if( xTaskResumeAll() == pdFALSE )
                {
                    portYIELD_WITHIN_API();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                prvUnlockQueue( pxQueue );
                ( void ) xTaskResumeAll();
            }
        }
        else
        {
            prvUnlockQueue( pxQueue );
            ( void ) xTaskResumeAll();
            
            if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
            {
                traceQUEUE_RECEIVE_FAILED( pxQueue );
                return errQUEUE_EMPTY;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }                                                                                                            
}

队列写数据 xQueueGenericSend 解析

BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
-> 
    for( ;; )
    {
    taskENTER_CRITICAL();    // 关中断 portDISABLE_INTERRUPTS();
    {

        if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )    // 判断是否有空间写数据
        {
        // 有空间写数据
            traceQUEUE_SEND( pxQueue );
            xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
       // 写数据 

            if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )          // 判断xTasksWaitingToReceive队列里是否有等待的任务
            {
                if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) // 1、将要写的任务从xTasksWaitingToReceive移除;2、将要写的任务从DelayList移动到ReadyList
                {

                    queueYIELD_IF_USING_PREEMPTION();    //让出CPU使用权
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }                                

            else if( xYieldRequired != pdFALSE )
            {

                queueYIELD_IF_USING_PREEMPTION();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        
        
        taskEXIT_CRITICAL();    // 开中断
        return pdPASS;          // 返回成功
    }
    else
    {
        if( xTicksToWait == ( TickType_t ) 0 )
        {
        
            taskEXIT_CRITICAL();
                
            traceQUEUE_SEND_FAILED( pxQueue );
            return errQUEUE_FULL;         // 返回队列已满
        }
        else if( xEntryTimeSet == pdFALSE )
        {
       
            vTaskInternalSetTimeOutState( &xTimeOut ); // 阻塞时间被指定,所以配置超时结构。 
            xEntryTimeSet = pdTRUE;
        }
        else
        {
        
        mtCOVERAGE_TEST_MARKER();
        }
    }
}
taskEXIT_CRITICAL();    // 开中断


vTaskSuspendAll();
prvLockQueue( pxQueue );

        
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
    if( prvIsQueueFull( pxQueue ) != pdFALSE )
    {
        traceBLOCKING_ON_QUEUE_SEND( pxQueue );
        // 1、当前的任务加入到队列的xTasksWaitingToSend链表中;
        // 2、当前的任务从ReadyList移动到DelayList                
        vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
        prvUnlockQueue( pxQueue );
    
        if( xTaskResumeAll() == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
    }
    else
    {

        prvUnlockQueue( pxQueue );
        ( void ) xTaskResumeAll();
    }
}
else
{

    prvUnlockQueue( pxQueue );
    ( void ) xTaskResumeAll();
    
    traceQUEUE_SEND_FAILED( pxQueue );
    return errQUEUE_FULL;
}
}

互斥访问与回环队列 内部实现框图

在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bazinga bingo

您的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值