刘火良 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;

}

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

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

相关文章

Uniapp项目运行到微信小程序、H5、APP等多个平台教程

摘要&#xff1a;Uniapp作为一款基于Vue.js的跨平台开发框架&#xff0c;支持“一次开发&#xff0c;多端部署”。本文将手把手教你如何将Uniapp项目运行到微信小程序、H5、APP等多个平台&#xff0c;并解析常见问题。 一、环境准备 在开始前&#xff0c;请确保已安装以下工具…

100天精通Python(爬虫篇)——第115天:爬虫在线小工具_Curl转python爬虫代码工具(快速构建初始爬虫代码)

文章目录 一、curl是什么&#xff1f;二、爬虫在线小工具&#xff08;牛逼puls&#xff09;三、实战操作 一、curl是什么&#xff1f; 基本概念&#xff1a;curl 支持多种协议&#xff0c;如 HTTP、HTTPS、FTP、SFTP 等&#xff0c;可用于从服务器获取数据或向服务器发送数据&a…

[内网安全] Windows 域认证 — Kerberos 协议认证

&#x1f31f;想系统化学习内网渗透&#xff1f;看看这个&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01&#xff1a;Kerberos 协议简介 Kerberos 是一种网络认证协议&#xff0c;其设计目标是通过密钥系统为客户机 / 服务器应用程序提供强大的认证服务。该认证过…

PyTorch中的损失函数:F.nll_loss 与 nn.CrossEntropyLoss

文章目录 背景介绍F.nll_loss什么是负对数似然损失&#xff1f;应用场景 nn.CrossEntropyLoss简化工作流程内部机制 区别与联系 背景介绍 无论是图像分类、文本分类还是其他类型的分类任务&#xff0c;交叉熵损失&#xff08;Cross Entropy Loss&#xff09;都是最常用的一种损…

案例1_3:流水灯

文章目录 文章介绍原理图&#xff08;同案例1_2&#xff09;代码效果图 文章介绍 原理图&#xff08;同案例1_2&#xff09; 代码 #include <reg51.h> // 包含头文件void delay(unsigned int time) {unsigned int i, j;for (i 0; i < time; i)for (j 0; j < 1…

基于物联网技术的电动车防盗系统设计(论文+源码)

1总体设计 本课题为基于物联网技术的电动车防盗系统&#xff0c;在此将整个系统架构设计如图2.1所示&#xff0c;其采用STM32F103单片机为控制器&#xff0c;通过NEO-6M实现GPS定位功能&#xff0c;通过红外传感器检测电瓶是否离开位&#xff0c;通过Air202 NBIOT模块将当前的数…

学习知识的心理和方法杂记-02

本文简单记录下我个人对大脑学习模式的认识。 人脑的基本能力是什么&#xff1f; 接收输入的能力。语言和声音 视觉图像 触觉 嗅觉 味觉等。 存储能力。人脑存储能力背后的物理化学结构我们人类目前还无法完全认知&#xff0c;但是存储的目标物一定是人可以通过五官获得的形…

国产化替换案例:CACTER邮件网关为Groupwise系统加固邮件安全防线

电子邮件作为企业信息流转的命脉&#xff0c;承载着商业机密与客户数据。然而&#xff0c;网络攻击手段日益复杂&#xff0c;钓鱼邮件等威胁正快速侵蚀企业安全防线。据《2024年第四季度企业邮箱安全性研究报告》显示&#xff0c;2024年Q4企业邮箱用户遭遇的钓鱼邮件数量激增至…

3.使用ElementUI搭建侧边栏及顶部栏

1. 安装ElementUI ElementUI是基于 Vue 2.0 的桌面端组件库。使用之前&#xff0c;需要在项目文件夹中安装ElementUI&#xff0c;在终端中输入以下命令&#xff0c;进行安装。 npm i element-ui -S并在main.js中引入ElementUI 2. 使用elmentUI组件进行页面布局 2.1 清空原…

C++并发以及多线程的秘密

1.基础概念 并发&#xff08;Concurrency&#xff09; 并发是指在同一时间段内&#xff0c;多个任务看起来像是同时执行的。并发并不一定意味着真正的同时执行&#xff0c;它可以是通过时间片轮转等方式在多个任务之间快速切换&#xff0c;让用户感觉多个任务在同时进行。并发…

从零开始实现大语言模型(十四):高阶训练技巧

1. 前言 预训练大语言模型的流程与训练普通神经深度网络模型本质上并没有任何不同。可以使用深度学习实践中已经被证明非常有效的高阶训练技巧&#xff0c;优化大语言模型预训练流程&#xff0c;使大语言模型预训练效率更高&#xff0c;训练过程更稳定。 本文介绍深度学习领域…

利用EasyCVR平台打造化工园区视频+AI智能化监控管理系统

化工园区作为化工产业的重要聚集地&#xff0c;其安全问题一直是社会关注的焦点。传统的人工监控方式效率低下且容易出现疏漏&#xff0c;已经难以满足日益增长的安全管理需求。 基于EasyCVR视频汇聚平台构建的化工园区视频AI智能化应用方案&#xff0c;能够有效解决这些问题&…

GB28181视频监控流媒体平台LiveGBS如何自定义收流端口区间以便减少收流端口数或解决端口冲突问题

LiveGBS GB28181流媒体服务在接收视频的时候默认是使用30000-30249&#xff0c; webrtc流播放端口区间默认是UDP的30250-30500区间。有些网络环境不方便开放这么大的端口区间&#xff0c;下面介绍下如何修改配置这个区间。 从页面上修改这个区间&#xff0c;端口区间尽量设置大…

Qt:事件

目录 处理事件 鼠标事件 键盘事件 定时器事件 窗口事件 虽然 Qt 是跨平台的 C 开发框架&#xff0c;Qt 的很多能力其实是操作系统提供的 只不过 Qt 封装了系统的 API 事件 前面学习过信号槽&#xff1a; 用户进行的各种操作&#xff0c;就可能会产生出信号&#xff0c;可以…

责任链模式:优雅处理复杂流程的设计艺术

引言 在软件设计中&#xff0c;我们经常会遇到需要按特定顺序处理请求的场景。例如&#xff0c;一个订单处理系统可能需要经过验证、付款、物流安排和客户通知等多个步骤。如果我们将这些步骤硬编码在一个方法中&#xff0c;代码将变得臃肿且难以维护。这时&#xff0c;责任链…

【STM32】玩转IIC之驱动MPU6050及姿态解算

目录 前言 一.MPU6050模块介绍 1.1MPU6050简介 1.2 MPU6050的引脚定义 1.3MPU6050寄存器解析 二.MPU6050驱动开发 2.1 配置寄存器 2.2对MPU6050寄存器进行读写 2.2.1 写入寄存器 2.2.2读取寄存器 2.3 初始化MPU6050 2.3.1 设置工作模式 2.3.2 配置采样率 2.3.3 启…

【ThreeJS Basics 09】Debug

文章目录 简介从 dat.GUI 到 lil-gui例子安装 lil-gui 并实例化不同类型的调整改变位置针对非属性的调整复选框颜色 功能/按钮调整几何形状文件夹调整 GUI宽度标题关闭文件夹隐藏按键切换 结论 简介 每一个创意项目的一个基本方面是能够轻松调整。开发人员和参与项目的其他参与…

【Pandas】pandas Series explode

Pandas2.2 Series Computations descriptive stats 方法描述Series.argsort([axis, kind, order, stable])用于返回 Series 中元素排序后的索引位置的方法Series.argmin([axis, skipna])用于返回 Series 中最小值索引位置的方法Series.argmax([axis, skipna])用于返回 Series…

电脑网络出现问题!简单的几种方法解除电脑飞行模式

在某些情况下&#xff0c;您可能需要关闭电脑上的飞行模式以便重新连接到 Wi-Fi、蓝牙或其他无线网络。本教程中简鹿办公将指导您如何在 Windows 和 macO S操作系统上解除飞行模式。 一、Windows 系统下解除飞行模式 通过快捷操作中心 步骤一&#xff1a;点击屏幕右下角的通知…

nature genetics | SCENT:单细胞多模态数据揭示组织特异性增强子基因图谱,并可识别致病等位基因

–https://doi.org/10.1038/s41588-024-01682-1 Tissue-specific enhancer–gene maps from multimodal single-cell data identify causal disease alleles 研究团队和单位 Alkes L. Price–Broad Institute of MIT and Harvard Soumya Raychaudhuri–Harvard Medical S…