当前位置: 首页 > article >正文

刘火良 FreeRTOS内核实现与应用之1——列表学习

重要数据

节点的命名都以_ITEM后缀进行,链表取消了后缀,直接LIST

普通的节点数据类型

/* 节点结构体定义 */

struct xLIST_ITEM

{

    TickType_t xItemValue;             /* 辅助值,用于帮助节点做顺序排列 */            

    struct xLIST_ITEM *  pxNext;       /* 指向链表下一个节点 */      

    struct xLIST_ITEM *  pxPrevious;   /* 指向链表前一个节点 */  

    void * pvOwner;                    /* 指向拥有该节点的内核对象,通常是TCB */

    void *  pvContainer;               /* 指向该节点所在的链表 */

};

typedef struct xLIST_ITEM ListItem_t;  /* 节点数据类型重定义 */



迷你节点数据类型

/* mini节点结构体定义,作为双向链表的结尾

   因为双向链表是首尾相连的,头即是尾,尾即是头 */

struct xMINI_LIST_ITEM

{

    TickType_t xItemValue;                      /* 辅助值,用于帮助节点做升序排列 */

    struct xLIST_ITEM *  pxNext;                /* 指向链表下一个节点 */

    struct xLIST_ITEM *  pxPrevious;            /* 指向链表前一个节点 */

};

typedef struct xMINI_LIST_ITEM MiniListItem_t;  /* 最小节点数据类型重定义 */

链表数据类型

/* 链表结构体定义 */

typedef struct xLIST

{

    UBaseType_t uxNumberOfItems;    /* 链表节点计数器 */

    ListItem_t *  pxIndex;          /* 链表节点索引指针 */

    MiniListItem_t xListEnd;        /* 链表最后一个节点 */

} List_t;

函数

1. 链表插入函数  vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )

升序插入函数

新的节点项插入后,需要解开原来的链接,建立新的链接:

语句1:向后看:新的节点项指向插入出(后面的)

pxNewListItem->pxNext = pxIterator->pxNext; // 插入,建立新的链接;

语句2:向前看:插入出(后面的)指向新的节点项

pxNewListItem->pxNext->pxPrevious = pxNewListItem; // 插入,建立新的链接;

语句3:向前看:新的节点项的前面为插入出(前面的)

pxNewListItem->pxPrevious = pxIterator; // 插入,建立新的链接;

语句4:向后看:插入出(前面的)指向新的节点项

pxIterator->pxNext = pxNewListItem;// 插入,建立新的链接;

/* 将节点按照升序排列插入到链表 */
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
    ListItem_t *pxIterator;
    
    /* 获取节点的排序辅助值 */
    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

    /* 寻找节点要插入的位置 */
    if( xValueOfInsertion == portMAX_DELAY )
    {
        pxIterator = pxList->xListEnd.pxPrevious;
    }
    else
    {
        for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
             pxIterator->pxNext->xItemValue <= xValueOfInsertion; 
             pxIterator = pxIterator->pxNext )
        {
            /* 没有事情可做,不断迭代只为了找到节点要插入的位置 */            
        }
    }

    pxNewListItem->pxNext = pxIterator->pxNext;
    pxNewListItem->pxNext->pxPrevious = pxNewListItem;
    pxNewListItem->pxPrevious = pxIterator;
    pxIterator->pxNext = pxNewListItem;

    /* 记住该节点所在的链表 */
    pxNewListItem->pvContainer = ( void * ) pxList;

    /* 链表节点计数器++ */
    ( pxList->uxNumberOfItems )++;
}

2. 链表尾部插入函数  void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

根节点既是头部也是尾部,当Item4插入,调用vListInsertEnd,插入如图所示位置,尾部插入

/* 将节点插入到链表的尾部 */

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

{

    ListItem_t * const pxIndex = pxList->pxIndex;

    pxNewListItem->pxNext = pxIndex;

    pxNewListItem->pxPrevious = pxIndex->pxPrevious;

    pxIndex->pxPrevious->pxNext = pxNewListItem;

    pxIndex->pxPrevious = pxNewListItem;

    /* 记住该节点所在的链表 */

    pxNewListItem->pvContainer = ( void * ) pxList;

    /* 链表节点计数器++ */

    ( pxList->uxNumberOfItems )++;

}

3. 链表删除节点函数 

删除节点,解开原来的链接,建立新的链接:

函数中为何会修改:pxList->pxIndex = pxItemToRemove->pxPrevious,

上面的建立函数一直没有修改链表中根节点的索引值的,索引值一直是指向根节点内部的xListEnd(根节点初始化的时候设置的。),既然建立的时候没有改变,为何删除的时候改变?

我的理解是保护用的,其实用处不大

/* 将节点从链表中删除 */

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )

{

    /* 获取节点所在的链表 */

    List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;

    pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

    /* Make sure the index is left pointing to a valid item. */

    if( pxList->pxIndex == pxItemToRemove )

    {

        pxList->pxIndex = pxItemToRemove->pxPrevious;

    }

    /* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */

    pxItemToRemove->pvContainer = NULL;

   

    /* 链表节点计数器-- */

    ( pxList->uxNumberOfItems )--;

    /* 返回链表中剩余节点的个数 */

    return pxList->uxNumberOfItems;

}

相关文章:

刘火良 FreeRTOS内核实现与应用之1——列表学习

重要数据 节点的命名都以_ITEM后缀进行&#xff0c;链表取消了后缀&#xff0c;直接LIST 普通的节点数据类型 /* 节点结构体定义 */ struct xLIST_ITEM { TickType_t xItemValue; /* 辅助值&#xff0c;用于帮助节点做顺序排列 */ struct xLIST_I…...

本地部署Navidrome个人云音乐平台随时随地畅听本地音乐文件

文章目录 前言1. 安装Docker2. 创建并启动Navidrome容器3. 公网远程访问本地Navidrome3.1 内网穿透工具安装3.2 创建远程连接公网地址3.3 使用固定公网地址远程访问 前言 今天我要给大家安利一个超酷的私有化音乐神器——Navidrome&#xff01;它不仅让你随时随地畅享本地音乐…...

数据集构建与训练前准备

训练数据集目录结构与格式 作者笨蛋学法&#xff0c;先将其公式化&#xff0c;后面逐步自己进行修改&#xff0c;读者觉得看不懂可以理解成&#xff0c;由结果去推过程&#xff0c;下面的这个yaml文件就是结果&#xff0c;我们去推需要的文件夹(名字可以不固定&#xff0c;但是…...

jenkins+ant+jmeter生成的测试报告空白

Jenkins能正常构建成功&#xff0c;但是打开Jenkins上的测试报告&#xff0c;则显示空白 在网上找了很多文章&#xff0c;结果跟别人对比测试报告的配置&#xff0c;发现自己跟别人写的不一样 所以跟着别人改&#xff0c;改成一样的再试试 结果&#xff0c;好家伙&#xff0…...

利用阿里云Atlas地区选择器与Plotly.js实现数据可视化与交互

在数据科学与可视化领域&#xff0c;交互式图表和地图应用越来越成为数据分析和展示的重要手段。本文将介绍如何结合阿里云Atlas地区选择器与Plotly.js&#xff0c;创建动态交互式的数据可视化应用。 一、阿里云Atlas地区选择器简介 阿里云Atlas是阿里云的一款数据可视化产品…...

行为级建模

1、结构化过程语句 verilog有两种结构化过程语句&#xff1a; always initial verilog本质上是并发的。 //声明初值//方法一 reg clk ; initialclk 1b0 ;//方法二 reg clk 1b0 ;2、过程赋值语句 阻塞赋值 非阻塞赋值 非阻塞赋值可以避免竞争&#xff1a;…...

linux安装java8 sdk,使用 tar.gz安装包手动安装

1. 下载 Java 8 SDK 首先&#xff0c;需要从 Oracle 的官方网站或 OpenJDK 的网站下载 Java 8 的 .tar.gz 文件。并上传到服务器 2. 解压 JDK 下载完成后&#xff0c;使用 tar 命令解压文件。打开服务器终端&#xff0c;然后使用以下命令&#xff1a; tar -xvzf jdk-8uXXX-…...

6.聊天室环境安装 - Ubuntu22.04 - elasticsearch(es)的安装和使用

目录 介绍安装安装kibana安装ES客户端使用 介绍 Elasticsearch&#xff0c; 简称 ES&#xff0c;它是个开源分布式搜索引擎&#xff0c;它的特点有&#xff1a;分布式&#xff0c;零配置&#xff0c;自动发现&#xff0c;索引自动分片&#xff0c;索引副本机制&#xff0c;res…...

【python爬虫】酷狗音乐爬取练习

注意&#xff1a;本次爬取的音乐仅有1分钟试听&#xff0c;仅作学习爬虫的原理&#xff0c;完整音乐需要自行下载客户端。 一、 初步分析 登陆酷狗音乐后随机选取一首歌&#xff0c;在请求里发现一段mp3文件&#xff0c;复制网址&#xff0c;确实是我们需要的url。 复制音频的…...

计算机视觉cv2入门之图像空域滤波(待补充)

空域滤波 空域滤波是指利用像素及像素领域组成的空间进行图像增强的方法。这里之所以用滤波这个词,是因为借助了频域里的概念。事实上空域滤波技术的效果与频域滤波技术的效果可以是等价的&#xff0c;而且有些原理和方法也常借助频域概念来解释。 原理和分类 空域滤波是在图…...

杂项知识笔记搜集

1.pygame pygame可以画出来图形界面&#xff0c;pygame Python仓库 PyGame游戏编程_游戏程序设计csdn-CSDN博客 2.V4L2库 V4L2是Linux上的Camera采集器的框架 Video for Linux &#xff0c;是从Linux2.1版本开始支持的。HDMI视频采集卡采集到的视频通过USB3.0输出&#xff0…...

代码随想录算法训练营第六十一天 | 108. 冗余连接 109. 冗余连接II

108. 冗余连接 题目链接&#xff1a;KamaCoder 文档讲解&#xff1a;代码随想录 状态&#xff1a;AC Java代码&#xff1a; import java.util.*;class Main {public static int[] father;public static void main(String[] args) {Scanner scan new Scanner(System.in);int n…...

选择排序算法的SIMD优化

一、优化原理 将查找数组最小值索引的SIMD优化的函数嵌入选择排序主循环,优化最耗时的最小值查找环节,同时保留选择排序的交换逻辑。 二、关键改造步骤 1)最小值查找模块化 复用SIMD优化的 find_min_index_simd函数。 2)动态子数组处理 每次循环处理 arr[i..n-1] 子数…...

Java本地方法根据线上地址下载图片到本地然后返回本地可以访问的地址

【需求】A和B两台服务器&#xff0c;A是云服务器&#xff0c;B是本地服务器&#xff0c;A和B上部署了一模一样的springboot代码&#xff0c;代码分为前后端&#xff0c;其中在B上前端请求先请求B的后端然后B转发到A的后端&#xff0c;然后A返回给B&#xff0c;B再返回给B的前端…...

游戏引擎学习第149天

今日回顾与计划 在今天的直播中&#xff0c;我们将继续进行游戏的开发工作&#xff0c;目标是完成资产文件&#xff08;pack file&#xff09;的测试版本。目前&#xff0c;游戏的资源&#xff08;如位图和声音文件&#xff09;是直接从磁盘加载的&#xff0c;而我们正在将其转…...

SpringBoot Test详解

目录 spring-boot-starter-test 1、概述2、常用注解 2.1、配置类型的注解2.2、Mock类型的注解2.3、自动配置类型的注解2.4、启动测试类型的注解2.5、相似注解的区别和联系 3、SpringBootTest和Junit的使用 3.1、单元测试3.2、集成测试 4、MockMvc 4.1、简单示例4.2、自动配置4…...

PyCharm 接入 DeepSeek、OpenAI、Gemini、Mistral等大模型完整版教程(通用)!

PyCharm 接入 DeepSeek、OpenAI、Gemini、Mistral等大模型完整版教程&#xff08;通用&#xff09;&#xff01; 当我们成功接入大模型时&#xff0c;可以选中任意代码区域进行解答&#xff0c;共分为三个区域&#xff0c;分别是选中区域、提问区域以及回答区域&#xff0c;我…...

升级到碳纤维齿轮是否值得?

引言&#xff1a;当齿轮开始“减肥” 在F1赛车的变速箱里&#xff0c;一个齿轮的重量减轻100克&#xff0c;就能让圈速提升0.1秒&#xff1b; 在无人机旋翼传动系统中&#xff0c;轻量化齿轮可延长续航时间15%&#xff1b; 甚至在高端机械腕表中&#xff0c;碳纤维齿轮的引入…...

基于SpringBoot+Vue的瑜伽课体验课预约系统【附源码】

基于SpringBootVue的瑜伽课体验课预约系统 一、系统技术说明二、运行说明三、系统的演示四、系统的核心代码演示 一、系统技术说明 框架&#xff1a;SpringbootVue 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软…...

文章被检测出是AI写的怎么办?

随着人工智能技术的飞速发展&#xff0c;AI辅助写作工具逐渐普及&#xff0c;为学生、科研人员以及创作者带来了诸多便利。然而&#xff0c;随之而来的是对学术诚信和内容原创性的担忧。当文章被检测出是AI写作时&#xff0c;应该如何应对&#xff1f;本文将探讨这一问题&#…...

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14基础固定表头示例

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

【英伟达AI论文】多模态大型语言模型的高效长视频理解

摘要&#xff1a;近年来&#xff0c;基于视频的多模态大型语言模型&#xff08;Video-LLMs&#xff09;通过将视频处理为图像帧序列&#xff0c;显著提升了视频理解能力。然而&#xff0c;许多现有方法在视觉主干网络中独立处理各帧&#xff0c;缺乏显式的时序建模&#xff0c;…...

[Lc10_hash] 总结 | 两数之和 | 字符重排 | 存在重复元素 i ii | 字母异位词分组

目录 1.介绍 2.两数之和 题解 3.面试题 01.02. 判定是否互为字符重排 题解 4.存在重复元素 题解 5.存在重复元素 II 题解 ⭕6.字母异位词分组 题解 1.介绍 哈希表是什么? 存储数据的容器前文&#xff1a;[C_] set | map | unordered_map 有什么用呢&#xff1f;…...

缓存之美:Guava Cache 相比于 Caffeine 差在哪里?

大家好&#xff0c;我是 方圆。本文将结合 Guava Cache 的源码来分析它的实现原理&#xff0c;并阐述它相比于 Caffeine Cache 在性能上的劣势。为了让大家对 Guava Cache 理解起来更容易&#xff0c;我们还是在开篇介绍它的原理&#xff1a; Guava Cache 通过分段&#xff08;…...

小组件适配屏幕主题色

iOS 18 新增Home screen Tint Color&#xff08;色调&#xff09;选择&#xff0c;用户可以通过以下方式自定义主屏幕颜色&#xff0c;并且小组件&#xff0c;APP 图标也会跟随改颜色。 比如说意料之外的小组件&#xff08;不兼容&#xff09; 白色部分内部应该还有其他显示内…...

IO学习---->线程

1.创建两个线程&#xff0c;分支线程1拷贝文件的前一部分&#xff0c;分支线程2拷贝文件的后一部分 #include <head.h> sem_t sem; long half_size 0; // 全局变量&#xff0c;供所有线程共享void* product(void *arg) {FILE *src fopen("IO.text", "…...

个人记录,Unity资源解压和管理插件

就是经典的两个AssetStudio 和 Ripper 没有什么干货&#xff0c;就是记录一下&#xff0c;内容没有很详细 AssetStudio 说错了&#xff0c;AssetStudio比较出名&#xff08;曾经&#xff09;&#xff0c;但好像堕落了 这个工具有个好处就是分类选择&#xff0c;&#xff08;…...

Synology 部署的 WordPress 無法升級至最新版本時,可以透過以下改良版指南進行排查和解決。

當 Synology 部署的 WordPress 無法升級至最新版本時&#xff0c;可以透過以下改良版指南進行排查和解決。我對內容進行了補充和重新組織&#xff0c;希望能幫助你更高效地處理這類問題&#xff1a; 權限相關問題處理 檢查文件和目錄權限&#xff1a; 確保 WordPress 安裝目錄…...

Java反射与动态代理:框架设计的基石

一、反射机制深度解剖&#xff08;Java 17新特性&#xff09; 1. Class对象获取六大途径 // 1. 类名.class Class<?> clazz1 String.class; // 2. 对象.getClass() String str ""; Class<?> clazz2 str.getClass(); // 3. Class.forName(…...

day19-前端Web——Vue3+TS+ElementPlus

目录 1. Vue工程化1.1 介绍1.2 环境准备1.2.1 NodeJS安装双击安装包选择安装目录验证NodeJS环境变量配置npm的全局安装路径 1.3 Vue项目-创建1.4 Vue项目开发流程1.5 API风格1.6 案例 2. TS2.1 概述2.2 快速入门2.3 常用类型2.3.1 基础类型2.3.2 联合类型2.3.3 函数类型2.3.4 对…...