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

news2024/11/18 7:28:32

文章目录

  • 前言
  • 一、队列结构体分析
  • 二、创建队列
  • 三、读写队列源码分析
    • 1.读队列源码分析
    • 2.写队列源码分析
  • 总结


前言

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

一、队列结构体分析

在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有重要的意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1155662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL数据库的存储引擎,底层存储结构,事物隔离级别,索引,日志等

存储引擎 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表而不是基于库的&#xff0c;所以存储引擎也可以被称为表引擎。 默认存储引擎是InnoDB。 InnoDB 在 MySQL 5.5 之后&#xff0c;InnoDB 是默认的 MySQL 引擎。 1.支持事务 2.行级锁…

YOLOv5/YOLOv7改进: AIFI (尺度内特征交互)助力YOLO | YOLO终结者?RT-DETR一探究竟

💡💡💡本文全网首发独家改进: AIFI (尺度内特征交互)助力YOLO ,提升尺度内和尺度间特征交互能力,同时降低多个尺度的特征之间进行注意力运算,计算消耗较大等问题 推荐指数:五星 AIFI | 亲测在多个数据集能够实现涨点 💡💡💡Yolov5/Yolov7魔术师,独家首…

Windows11无法打开Photoshop CC 2017问题解决

情况描述&#xff1a; Windows11上&#xff0c;双击Photoshop CC 2017没反应 解决办法&#xff1a; 此时需要启动Windows的“事件查看器”来确认问题出在哪里。可以直接通过开始菜单搜索启动&#xff0c;也可以通过右键点击“此电脑”->“管理”&#xff0c;然后找到事件查…

解密杭州亚运背后科技:核心系统100%上云,20多项全球首创智能应用

10月31日&#xff0c;2023杭州云栖大会&#xff0c;杭州亚运会信息技术中心执行指挥长、杭州亚组委广播电视和信息技术部副部长张鸽以《科技创新在亚运舞台精彩绽放》为主题&#xff0c;分享了杭州亚运会的智能亚运实践。 杭州亚运会打造了史上首个全覆盖的数字化服务体系&…

港府Web3宣言周年思考:合规困境中的“隐患”

出品&#xff5c;欧科云链研究院 作者&#xff5c;毕良寰 距离《有关虚拟资产在港发展的政策宣言》已过去一年&#xff0c;我们欧科云链研究院在分析全球几个主要国家和地区对Web3的监管政策及态度后&#xff0c;对港府的雄心壮志充满期待。然而&#xff0c;由于近期一些庞氏骗…

学习redis之前的泛泛而谈(特性介绍,应用场景,Ubuntu安装与通用命令介绍)

文章目录 前言关于分布式系统Redis特性Redis应用场景Redis5安装redis命令最核心的两个命令&#xff1a;get和setkeysexitsdelexpirettlredis中key的过期策略type redis数据类型的内部实现方式redis的单线程 前言 redis最重要的概念&#xff1a;在内存中存储数据 为什么要设计一…

MySQL(4):运算符

算术运算符 算术运算符主要用于数学运算&#xff0c;其可以连接运算符前后的两个数值或表达式&#xff0c;对数值或表达式进行加&#xff08;&#xff09;、减&#xff08;-&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;和取模&#xff08;%&#…

在uni-app中使用ECharts - 配置四种不同的图表

&#x1f468;‍&#x1f9b0;博主&#xff1a;小猫娃来啦 &#x1f468;‍&#x1f9b0;文章核心&#xff1a;在uni-app中使用ECharts - 配置四种不同的图表 文章目录 前言安装ECharts插件引入ECharts库创建Charts实例和图表容器配置和渲染图表配置柱状图配置折线图配置饼图配…

详解final, abstract, interface关键字

一.final关键字 1.final关键字介绍 ——final关键字可以去修饰类、方法、属性和局部变量 2.final关键字的作用 1&#xff09;final修饰类&#xff0c;这个类不能被其他类继承 2&#xff09;final修饰方法&#xff0c;方法不能被重写 3&#xff09;final修饰属性&#xff0c;属…

通过shiro框架记录用户登录,登出及浏览器关闭日志

背景&#xff1a; 公司项目之前使用websocket记录用户登录登出日志及浏览器关闭记录用户登出日志&#xff0c;测试发现仍然存在问题&#xff0c; 问题一&#xff1a;当浏览器每次刷新时websocket其实是会断开重新连接的&#xff0c;因此刷新一下就触发记录登出的日志&#xff0…

41.排序练习题(王道2023数据结构第8章综合练习)

试题1&#xff08;王道8.3.3节综合练习2&#xff09;&#xff1a; 编写双向冒泡排序算法&#xff0c;在正反两个方向交替扫描。即第一趟把关键字最大的元素放在序列的最后面&#xff0c;第二趟把关键字最小的元素放在序列最前面&#xff0c;如此反复。 首先实现冒泡排序&…

FIFO 位宽转换

从8位转32位 module tb_fifo();reg clk,rst; initial beginclk0;forever #4.545 clk~clk; end initial beginrst1;#9.09 rst0; endreg [31:0] cnts; always (posedge clk or posedge rst) beginif(rst)begincnts < 32d0;endelsebegincnts < cnts 1b1;end endreg […

美国白宫发布总统令:鼓励AI以安全、可靠的方式发展

美国华盛顿时间10月30日&#xff0c;美国白宫官网发布了&#xff0c;关于发展安全、可靠和值得信赖的AI&#xff08;人工智能&#xff09;的拜登总统行政令。 白宫表示&#xff0c;该行政令为AI安全和保障制定了新标准&#xff0c;保护了用户的数据隐私&#xff0c;促进公平和…

英语——歌曲篇——only you

《only you》(只有你)赏析 很多人都听过The Platters(派特斯乐队)演唱的《only you》(只有你)这首歌曲&#xff0c;尤其是看过在周星驰和罗家英在《大话西游》里面演绎的"无厘头"版本后。 不过&#xff0c;又有几人知道&#xff0c;这首歌曲原来是经典浪漫影片《罗马…

C语言_常用数据类型地址的理解

常用基本数据类型&#xff1a; #include <stdio.h> #include <stdlib.h> #include <stdint.h>int main(){printf("基本数据类型:\n");printf("char: %d\n", sizeof(char));printf("int: %d\n", sizeof(int));printf("do…

1.6 基本安全设计准则

思维导图&#xff1a; 1.6 基本安全设计准则笔记 目标&#xff1a;理解和遵循一套广泛认可的安全设计准则&#xff0c;以指导保护机制的开发。 主要准则&#xff1a; 机制的经济性&#xff1a;安全机制应设计得简单、短小&#xff0c;便于测试和验证&#xff0c;减少漏洞和降…

linux系统的环境变量-搞清环境变量到底是什么

环境变量 引例环境变量常见的环境变量echoexportenvunsetset 通过代码获取环境变量使用第三个参数获取使用全局变量enviorn获取环境变量通过系统调用获取环境变量 环境变量具有全局属性main函数前两个参数的作用 引例 在linux系统中&#xff0c;我们使用ls命令&#xff0c;直接…

Python 算法高级篇:深度优先搜索和广度优先搜索的高级应用

Python 算法高级篇&#xff1a;深度优先搜索和广度优先搜索的高级应用 引言 1. 深度优先搜索&#xff08; DFS &#xff09;回顾2. 广度优先搜索&#xff08; BFS &#xff09;回顾3. 拓扑排序4. 连通性检测5. 最短路径问题6. 案例分析&#xff1a;社交网络分析7. 总结 引言 深…

剑指 Offer || 084.全排列||

题目 给定一个可包含重复数字的整数集合 nums &#xff0c;按任意顺序 返回它所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1…

【蓝桥杯选拔赛真题07】C++小球自由落体 青少年组蓝桥杯C++选拔赛真题 STEMA比赛真题解析

目录 C/C++小球自由落体 一、题目要求 1、编程实现 2、输入输出 二、算法分析