首页 > 编程语言 >FreeRTOS深入教程(队列内部机制和源码分析)

FreeRTOS深入教程(队列内部机制和源码分析)

时间:2023-11-01 14:35:05浏览次数:35  
标签:教程 FreeRTOS 队列 pxQueue 任务 pdFALSE 源码 xTicksToWait uxMessagesWaiting

(文章目录)


前言

本篇文章主要来为大家分析队列的内部机制和源码实现。

一、队列结构体分析

在FreeRTOS中队列会使用一个结构体来表示: 在这里插入图片描述 在这里插入图片描述 1.int8_t * pcHead 和 int8_t * pcWriteTo:这些指针指向队列存储区的头部和下一个可写入的位置。队列存储区是一个用于存储队列中数据项的缓冲区。

2.union:这个联合体 u 可以是两种不同类型之一:QueuePointers_t 或 SemaphoreData_t,这允许队列结构用于不同的用途,例如队列或信号量。

3.在QueuePointers_t 结构体中包含pcReadFrom指向当前读位置。

4.List_t xTasksWaitingToSend 和 List_t xTasksWaitingToReceive:这些是用于存储等待发送或接收数据的任务的链表。这些链表按任务的优先级排序,以确保高优先级的任务有更高的访问权。

5.volatile UBaseType_t uxMessagesWaiting:这是队列中当前待处理的数据项数量。

6.UBaseType_t uxLength:这是队列的长度,即它可以容纳的数据项数量,不是字节数。

7.UBaseType_t uxItemSize:这是队列中每个数据项的大小。

8.volatile int8_t cRxLock 和 volatile int8_t cTxLock:这些变量用于跟踪队列的锁状态。它们记录队列是否被锁定,并在锁定时记录发送到队列的数据项数量。

9.uint8_t ucStaticallyAllocated:这个变量用于标志队列内存的分配方式。如果设置为 pdTRUE,表示队列的内存是静态分配的,不应尝试释放内存。

10.struct QueueDefinition * pxQueueSetContainer:这个成员仅在配置中启用了队列集(configUSE_QUEUE_SETS为1)时有效。它指向包含此队列的队列集。

二、创建队列

队列由队列头和队列中的每一个元素组成:

故分配内存时需要包含队列头部和全部元素的大小 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

三、读写队列源码分析

读写队列主要涉及到 环形缓冲区、链表,共享资源的访问。

1.读队列源码分析

在写队列时首先需要先禁止任务调度,防止一个任务在写队列时,其他任务也来写队列导致出现错误。

taskENTER_CRITICAL();//禁止任务调度

判断当前队列中消息数量是否小于队列的长度

if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )

如果当前队列中消息数量小于队列的长度,那么就证明还可以写入数据。

调用prvCopyDataToQueue函数往队列中写入数据。

xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );

判断是否有任务在等待数据,如果有任务在等待数据,那么将这个任务从等待接收数据链表中移除,并且唤醒这个任务。

                        if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
                        {
                            if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                            {
                                /* The unblocked task has a priority higher than
                                 * our own so yield immediately.  Yes it is ok to do
                                 * this from within the critical section - the kernel
                                 * takes care of that. */
                                queueYIELD_IF_USING_PREEMPTION();
                            }
                            else
                            {
                                mtCOVERAGE_TEST_MARKER();
                            }
                        }

如果队列已满并且没有设置超时时间或者超时时间到了,那么就会返回错误,并且恢复中断,让任务可以重新调度。

                if( xTicksToWait == ( TickType_t ) 0 )
                {
                    /* The queue was full and no block time is specified (or
                     * the block time has expired) so leave now. */
                    taskEXIT_CRITICAL();

                    /* Return to the original privilege level before exiting
                     * the function. */
                    traceQUEUE_SEND_FAILED( pxQueue );
                    return errQUEUE_FULL;
                }

如果设置了超时时间,那么会调用vTaskPlaceOnEventList函数将当前任务挂入xTasksWaitingToSend 链表

        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
            if( prvIsQueueFull( pxQueue ) != pdFALSE )
            {
                traceBLOCKING_ON_QUEUE_SEND( pxQueue );
                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );

vTaskPlaceOnEventList函数

void vTaskPlaceOnEventList( List_t * const pxEventList,
                            const TickType_t xTicksToWait )
{
    configASSERT( pxEventList );

    /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE
     * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */

    /* Place the event list item of the TCB in the appropriate event list.
     * This is placed in the list in priority order so the highest priority task
     * is the first to be woken by the event.  The queue that contains the event
     * list is locked, preventing simultaneous access from interrupts. */
    vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) );

    prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
}

2.写队列源码分析

读取队列时也是需要禁止任务调度的,防止多个任务一起读取数据

taskENTER_CRITICAL();

首先判断队列中的数据量是否大于0,如果大于0就将队列中的数据读取出来,并且将uxMessagesWaiting减1。

           const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;

            /* Is there data in the queue now?  To be running the calling task
             * must be the highest priority task wanting to access the queue. */
            if( uxMessagesWaiting > ( UBaseType_t ) 0 )
            {
                /* Data available, remove one item. */
                prvCopyDataFromQueue( pxQueue, pvBuffer );
                traceQUEUE_RECEIVE( pxQueue );
                pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;

读取完数据后判断是否有任务在等待写数据,如果有任务在等待写数据那么就将这个任务从等待写数据链表中移除

                if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
                {
                    if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
                    {
                        queueYIELD_IF_USING_PREEMPTION();
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

如果没有设置超时时间,或者是时间到了那么就返回错误并且退出

                if( xTicksToWait == ( TickType_t ) 0 )
                {
                    /* The queue was empty and no block time is specified (or
                     * the block time has expired) so leave now. */
                    taskEXIT_CRITICAL();
                    traceQUEUE_RECEIVE_FAILED( pxQueue );
                    return errQUEUE_EMPTY;
                }

如果设置了超时时间那么就将当前读取数据任务挂入链表当中

        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
            /* The timeout has not expired.  If the queue is still empty place
             * the task on the list of tasks waiting to receive from the queue. */
            if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
            {
                traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
                vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
                prvUnlockQueue( pxQueue );

                if( xTaskResumeAll() == pdFALSE )
                {
                    portYIELD_WITHIN_API();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }

总结

本篇文章就讲解到这里,大家可以自己对FreeRTOS的源代码进行分析,分析源代码对学习FreeRTOS有重要的意义。

标签:教程,FreeRTOS,队列,pxQueue,任务,pdFALSE,源码,xTicksToWait,uxMessagesWaiting
From: https://blog.51cto.com/u_16153875/8122068

相关文章

  • Docker从了解到部署应用的详细教程
    一、Docker基础知识1、Docker(1)Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可以移植的容器中,然后发布到任何的linux机器上,可以实现虚拟化;(2)Docker容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低;2、Docker的应用场景(1)Web应用的自动化......
  • 无涯教程-React Native - 运行IOS
    如果您想在IOS模拟器中测试您的应用程序,则只需在终端中打开应用程序的根文件夹并运行-react-nativerun-ios上面的命令将启动模拟器并运行该应用程序。我们还可以指定我们要使用的设备。react-nativerun-ios--simulator"iPhone5s在模拟器中打开应用程序后,可以在IOS上按......
  • 直播平台源码,自定义下拉刷新控件
    直播平台源码,自定义下拉刷新控件 importFoundationimportUIKitimportSnapKitclassXRefreshControl:UIRefreshControl{  varobservation:NSKeyValueObservation?  varisLocalRefreshing:Bool=false  letindicator=UIProgressView(progressViewStyle:......
  • 无涯教程-React Native - 路由
    在本章中,我们将了解ReactNative中的导航。步骤1-安装路由首先,我们需要安装Router路由,我们将在本章中使用ReactNativeRouterFlux,您可以在终端的项目文件夹中运行以下命令。npmireact-native-router-flux--save步骤2-应用代码由于我们希望Router处理整个应用程序......
  • LIMS系统源码:从样品登记到检验全面管理实验室流程
    LIMS可用于管理完整的实验程序,从样品登记到检验、校核、审核到最终批准报告,建立在过程质量控制的基础上,对检测流程进行有效全面的管理,对影响质量的人、机、料、法、环因素加以控制,同时为质量改进提供数据依据。LIMS实验室信息管理系统,功能包括以下几个模块:委托管理:样品登记、样品接......
  • 无涯教程-React Native - 调试
    Reactnative提供了两种方法来帮助调试代码。在AppDeveloper菜单中您可以通过按command+D在IOS模拟器上打开开发人员菜单。在Android模拟器上,您需要按command+M。Reload                - 用于重新加载模拟器。您可以使用快捷键......
  • Metasploit使用教程-(反弹shell)
    Metasploit反弹shell 利用msfvenom生成一个反弹shell程序 msfvenom-lpayloads可以查看所有payloadWindows通用反向shell:windows/meterpreter/reverse  --基于TCP的反向链接反弹shell,使用起来很稳定。windows/meterpreter/reverse_http  --基于http方式的反......
  • 无涯教程-React Native - 环境设置
    您需要安装几件事来为ReactNative设置环境。我们将使用OSX作为构建平台。步骤1-安装create-react-native-app在系统中成功安装NodeJS和NPM之后,您可以继续安装create-react-native-app(全局显示如下)。C:\Users\Learnfk>npminstall-gcreate-react-native-app步骤2-创......
  • Kamailio 源码编译
    Kamailio源码编译一、环境1、OS:Debianbullseye2、版本:Kamailio-5.7.23、MySQL5.7 二、编译1、在Kamailio-5.7.2目录下执行如下指令,生产modules.lst文件makeFLAVOUR=kamailiocfg2、打开modules.lst文件,找到exclude_modules,将等号后面的db_mysql删除。然后执行编译......
  • fastapi搭建平台实战教程一:SQLAlchemy生成数据库数据
    除了falsk,SQLAlchemy也能很好的支持fastapi框架。首先创建一个main.pyfromfastapiimportFastAPIapp=FastAPI()@app.post("/register")defregister():[email protected]("/login")deflogin():...配置数据库创建db.py,初始化数据库连接对象fromsqlalche......