直接上源码分析

void vListInitialise( List_t * const pxList )
{

   pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );           /* 此时链表中只有一个列表项(结点) */

   pxList->xListEnd.xItemValue = portMAX_DELAY;            /* 辅助值,用来做升序 */

  pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );     

  pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd )

  pxList->uxNumberOfItems = ( UBaseType_t ) 0U;              /* 记录列表中节点的数量 */

}

void vListInitialiseItem( ListItem_t * const pxItem )
{

   /* 标记此节点属于哪个列表。初始化为NULL */

  pxItem->pxContainer = NULL;

}

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

{

  ListItem_t * const pxIndex = pxList->pxIndex;      /* 先拿到这个链表的索引,网上说这个索引指向列表项的头部,但是初始化并没有这个操作 */

  pxNewListItem->pxNext = pxIndex;            /* 新插入的节点的下一个节点就是这个pxIndex节点 ,新插入的节点指向了末尾节点 */
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;  /* pxIndex->pxPrevious 指向的是列表的末尾节点,pxNewListItem->pxPrevious 新插入的节点的上一个等于末尾的节点,不知道为什么要这样 */

  pxIndex->pxPrevious->pxNext = pxNewListItem;    /* pxIndex->pxPrevious->pxNext本来是指向自己,现在指向的是新节点,等于连接起来 */

  pxIndex->pxPrevious = pxNewListItem;        /* 基本操作了,链接节点 */

  pxNewListItem->pxContainer = pxList;    /* 标记状态 */

  ( pxList->uxNumberOfItems )++;    /* 节点加1,这里为什么加括号? */

}

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;      /* 如果要插入的节点的值等于最大值,那就插在End的前一个节点的位置 */
    }

  

else

{

  /*  首先pxIterator指向此链表的最后一个节点,判断新插入的节点的值和pxIterator下一个节点的值

      此时 pxIterator->pxNext->xItemValue就是首节点的值,(为什么是首节点,因为初始化pxIterator指向了End节点,pxIterator = ( ListItem_t * ) &( pxList->xListEnd ))

    如果插入的值大于pxIterator->pxNext->xItemValue(第一次是首节点的值),那么pxIterator=pxIterator->pxNext ,即指向下一个节点继续循环

    如果插入的值小于pxIterator->pxNext->xItemValue,那么就说明找到了要插入的地方

    那就是新插入的到pxIterator的后面,要插入的节点就是pxIterato和 pxIterato->next之间。

    */

  for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) {  }

}

   pxNewListItem->pxNext = pxIterator->pxNext;  /* 首先把 pxIterator->pxNext 赋值给 pxNewListItem->pxNext,让新列表项指向原本列表中下一个列表项 */

   pxNewListItem->pxNext->pxPrevious = pxNewListItem;  /*  把 pxNewListItem->pxNext(也就是原本列表中下一个列表项)的 pxNewListItem->pxNext->pxPrevious 成员指向待插入列表项 pxNewListItem,实现双向链表 */

      pxNewListItem->pxPrevious = pxIterator;    /* 新插入的上一个指向pxIterator,就是上面说的,新的节点插到pxIterator的后面 */

      pxIterator->pxNext = pxNewListItem;      /* pxIterator->pxNext : 原来的pxIterator节点  (此时只是插入节点,xIterator->pxNext一定要指向pxNewListItem,实现节点的链接)的下一个就是新的节点了 */

   pxNewListItem->pxContainer = pxList;    /* 老套路了 */  

          ( pxList->uxNumberOfItems )++; /* 列表项个数加1 */

}

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )

{

  List_t * const pxList = pxItemToRemove->pxContainer;    /* 得到要删除节点链表 */

  pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;  /* 这里就只是改变指针前后链接 */

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

  mtCOVERAGE_TEST_DELAY();    /* 这里为什么要存在空函数? */

  if( pxList->pxIndex == pxItemToRemove )    /* 很好理解,不做解释 */
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }

  pxItemToRemove->pxContainer = NULL;    /* 已经都删除节点了,这个节点的属主链表肯定不存在啊 */
     ( pxList->uxNumberOfItems )--;      /* 老套路了 */

  return pxList->uxNumberOfItems;    /* 返回这个链表还有几个节点 */

}

// 仍有疑问,希望有人看到能解答一下,在下感激不尽。

FreeRTOS链表实现的更多相关文章

  1. FreeRTOS --(1)链表

    转载自 https://blog.csdn.net/zhoutaopower/article/details/106550648 Based On FreeRTOS Kernel V10.3.1 1. ...

  2. FreeRTOS数据结构(一)--链表和链表项

    结构体定义 /*链表结构体*/ typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /*用于链表完整性检查*/ configLIST ...

  3. FreeRTOS 使用指南(转)

    源:FreeRTOS 使用指南 繁星电子开发团队制作 作为一个轻量级的操作系统,FreeRTOS 提供的功能包括:任务管理.时间管理.信号量.消息队列.内存管理.记录功能等,可基本满足较小系统的需要. ...

  4. FreeRTOS初步认识

    源:FreeRTOS初步认识 用了半天时间对FreeRTOS有了一个初步的认识,大概总结一下,其中混杂了系统实现和实际应用方面的问题. 现只是以应用为目的,实现方面待以后进一步研究. 1.FreeRT ...

  5. FreeRTOS代码剖析

    FreeRTOS代码剖析之1:内存管理Heap_1.c   FreeRTOS代码剖析之2:内存管理Heap_2.c   FreeRTOS(V8.0.1)系统之xTaskGenericCreate() ...

  6. FreeRTOS的内存管理

    FreeRTOS提供了几个内存堆管理方案,有复杂的也有简单的.其中最简单的管理策略也能满足很多应用的要求,比如对安全要求高的应用,这些应用根本不允许动态内存分配的. FreeRTOS也允许你自己实现内 ...

  7. FreeRTOS 动态内存管理

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 动态内存管理,动态内存管理是 FreeRTOS 非常重要的一项功能,前面 ...

  8. FreeRTOS内存管理

    简介 Freertos的内存管理分别在heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c个文件中,选择合适的一种应用于嵌入式项目中即可. 本文的图片中 红色部分B ...

  9. FreeRTOS基础知识

    前面一篇文章介绍了一些命名规范之类的基础知识,但是我觉得还缺少一定前言知识,就是裸机和操作系统有什么区别,为什么我们需要学freertos,因为招聘要求?那么为什么招聘网又会有这个要求呢?所以我们为什 ...

随机推荐

  1. sql注入--bool盲注,时间盲注

    盲注定义: 有时目标存在注入,但在页面上没有任何回显,此时,我们需要利用一些方法进行判断或者尝试得到数据,这个过程称之为盲注. 布尔盲注: 布尔盲注只有true跟false,也就是说它根据你的注入信息 ...

  2. 第16课 - make的隐式规则(下)

    第16课 - make的隐式规则(下) 1

  3. Linux打包压缩解压工具

    第1章      Linux 打包压缩解压工具一.压缩.解压工具 compress/uncompress gzip/gunzip bzip2/bunzip2/ bzcat xz/unxz/ xzcat ...

  4. html+css入门基础案例之页面设计

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. JVM_01 简介

    本篇仅仅是JVM的简介,关于更多的JVM细节,请参见本专题JVM: 计算机系统当中的JVM JVM是运行在操作系统之上的,并没有和硬件有直接的交互 Java代码一次编译,到处运行 HotSpot虚拟机 ...

  6. 集群实战(2):K8S集群节点退出加入操作

    以下报错网上其实也可以找到并解决,但是偏零碎我只是根据自己的在使用中遇到的问题做个汇总. 文章目录 首先删掉节点 node重新加入 参考文档 首先删掉节点 注意:以下操作都是在master下操作. 一 ...

  7. 重磅来袭 Vue 3.0 One Piece 正式发布

    代号为One Piece 的Vue3.0 在9月19日凌晨正式发布!! 此次vue3.0 为用户提供了全新的 composition-api 以及更小的包大小,和更好的 TypeScript 支持. ...

  8. Infor EAM:注重行业属性,实现对轨道交通线性资产的可视化管理

    Infor EAM:注重行业属性,实现对轨道交通线性资产的可视化管理 企业得利,一要开源,二要节流.而企业资产管理的目的,也正是从资产的角度出发,一方面通过相关资源与活动的合理安排提高设备可利用率.增 ...

  9. ribbon源码(4) 载均衡算法

    负载均衡算法模块主要的功能是从负载均衡器中获取服务器列表信息,根据算法选取出一个服务器. IRule 负载均衡算法接口 public interface IRule{ public Server ch ...

  10. 干货满满!关于Pycharm远程开发

    可以在Windows中使用Pycharm编写代码,而代码的调试运行可以使用远程服务器中的python解释器. 在本地创建好工程项目(或从git上clone下代码)后,用Pycharm打开: 打开「To ...