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

列表与列表项

认识列表和列表项

FreeRTOS 中的 列表(List) 和 列表项(ListItem)是其内核实现的核心数据结构,广泛用于任务调度、队列管理、事件组、信号量等模块。它们通过双向链表实现,支持高效的元素插入、删除和遍历操作。

1. 列表(List)
列表是 FreeRTOS 中用于管理多个列表项的容器,其结构定义在 "list.h" 中  
主要成员如下:
     - uxNumberOfItems: 当前列表中包含的列表项数量。
     - pxIndex: 指向列表中的一个列表项,用于遍历列表(如任务切换时遍历就绪列表)。
     - xListEnd: 列表的“结束标记”,是一个特殊的列表项,作为链表的头和尾的锚点。

列表特点:
     - 列表是一个双向循环链表,通过 "xListEnd "作为链表的起点和终点。
     - 列表项按 "xItemValue"(列表项的值)"升序排列",便于快速插入和查找(如任务优先级调度)。

 2. 列表项(ListItem)
列表项是链表的节点,定义在 "list.h" 中
主要成员如下:
     - pvOwner: 指向列表项的所有者(如任务控制块 `TCB_t`)。
     - pxContainer: 指向该列表项所属的列表。
     - pxPrevious/pxNext: 指向前一个和后一个列表项的指针。
     - xItemValue: 列表项的值,用于排序(如任务的优先级)。

 列表项特点:
     - 每个列表项可以动态插入或移除到不同的列表中。
     - 列表项的 "xItemValue"决定了它在列表中的位置(按升序排列)。

3. 列表和列表项的关系
- 列表通过 "xListEnd"作为根节点,所有列表项通过 "pxPrevious"和 "pxNext" 指针链接成一个环。
- 例如,FreeRTOS 的任务就绪列表(pxReadyTasksLists)是一个列表,每个任务的控制块(TCB)中的状态列表项(xStateListItem)会插入到对应的就绪列表中。

4. 应用场景
1. 任务管理  
   - 任务的就绪列表、阻塞列表、挂起列表均通过列表和列表项管理。
   - 例如,任务的 "xStateListItem" 会根据任务状态插入到不同的列表中。
   - 任务的优先级由 "xItemValue" 表示,列表按优先级排序。

2. 事件组、队列、信号量
   - 当任务等待事件或资源时,其事件列表项(如 xEventListItem)会被插入到事件或资源的等待列表中。

5. 常用操作函数
FreeRTOS 提供了一系列 API 操作列表和列表项:

列表操作:
     - vListInitialise(List_t *pxList): 初始化一个空列表。
     - vListInsert(List_t *pxList, ListItem_t *pxNewListItem): 按 "xItemValue" 升序插入列表项。
     - vListRemove(ListItem_t *pxItemToRemove): 从列表中移除某个列表项。

列表项操作:
     - vListInitialiseItem(ListItem_t *pxItem): 初始化列表项。
     - listSET_LIST_ITEM_OWNER(ListItem_t *pxListItem, void *pvOwner): 设置列表项的所有者(如任务句柄)。
     - listGET_LIST_ITEM_VALUE(ListItem_t *pxListItem): 获取列表项的值。

下面用代码演示列表项的插入、删除以及末尾插入:

1.插入列表项1,值为40

//列表任务
void list_task(void *pvParameters)
{vListInitialise( &TestList );//初始化列表1vListInitialiseItem(&ListItem1);//初始化列表项1vListInitialiseItem(&ListItem2);//初始化列表项2vListInitialiseItem(&ListItem3);//初始化列表项3ListItem1.xItemValue = 40;ListItem2.xItemValue = 60;ListItem3.xItemValue = 50;printf("----------------------------列表与列表项地址------------------------- \r\n");
printf("项目                         地址                                    \r\n");
printf("TestList                     %#x                         \r\n",(int)&TestList);
printf("TestList->pxIndex            %#x                 \r\n",(int)TestList.pxIndex);
printf("TestList->xListEnd           %#x             \r\n",(int)&(TestList.xListEnd));
printf("ListItem1                    %#x                   \r\n",(int)&ListItem1);
printf("ListItem2                    %#x                     \r\n",(int)&ListItem2);
printf("ListItem3                    %#x                     \r\n",(int)&ListItem3);//TestList插入列表项1
vListInsert(&TestList ,&ListItem1);//插入列表项函数
printf("---------------------------插入列表项ListItem1------------------------\r\n");
printf("TestList->xListEnd->pxNext        %#x       \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext                 %#x              \r\n",(int)(ListItem1.pxNext));
printf("----------------------------前后连接分割线----------------------------\r\n");
printf("TestList->xListEnd->pxPrevious    %#x   \r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious             %#x           \r\n",(int)(ListItem1.pxPrevious));
printf("------------------------------结束---------------------------------------\r\n");

用串口打印连接结果:

可以看出列表和列表项1进行了环形连接

2.紧接着上面的代码再插入列表项2,值为60

	//插入列表项2vListInsert(&TestList ,&ListItem2);
printf("--------------------------------再插入列表项ListItem2------------------------\r\n");
printf("TestList->xListEnd->pxNext        %#x       \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext                 %#x               \r\n",(int)(ListItem1.pxNext));
printf("ListItem2->pxNext                 %#x               \r\n",(int)(ListItem2.pxNext));printf("---------------------------------前后连接分割线-----------------------------\r\n");
printf("TestList->xListEnd->pxPrevious    %#x  \r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious             %#x          \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem2->pxPrevious             %#x          \r\n",(int)(ListItem2.pxPrevious));
printf("---------------------------------结束--------------------------------------\r\n");

用串口打印连接结果:

可以看出他们的连接方式

3.紧接着上面的代码再插入列表项3,值为50

//插入列表项3vListInsert(&TestList ,&ListItem3);
printf("---------------------------再插入列表项ListItem3------------------------\r\n");
printf("TestList->xListEnd->pxNext        %#x      \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext                %#x                \r\n",(int)(ListItem1.pxNext));
printf("ListItem2->pxNext                %#x              \r\n",(int)(ListItem2.pxNext));
printf("ListItem3->pxNext                %#x               \r\n",(int)(ListItem3.pxNext));printf("----------------------------前后连接分割线---------------------------------\r\n");
printf("TestList->xListEnd->pxPrevious    %#x \r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious             %#x          \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem2->pxPrevious             %#x         \r\n",(int)(ListItem2.pxPrevious));
printf("ListItem3->pxPrevious             %#x         \r\n",(int)(ListItem3.pxPrevious));
printf("-----------------------------------结束-----------------------------------\r\n");

用串口打印结果:

可以看出列表项3插在了列表项1和2之间,说明列表项的 "xItemValue"决定了它在列表中的位置(按升序排列)

4.紧接着上面的代码删除列表项2

//列表删除列表项2uxListRemove(&ListItem2);
printf("--------------------------------列表删除ListItem2------------------------\r\n");
printf("TestList->xListEnd->pxNext       %#x        \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext                %#x                \r\n",(int)(ListItem1.pxNext));
printf("ListItem3->pxNext                %#x                \r\n",(int)(ListItem3.pxNext));printf("-------------------------------前后连接分割线-----------------------------\r\n");
printf("TestList->xListEnd->pxPrevious    %#x   \r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious             %#x           \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem3->pxPrevious             %#x           \r\n",(int)(ListItem3.pxPrevious));
printf("---------------------------------结束--------------------------------------\r\n");

用串口打印结果:

可以看出ListItem3->pxNext  由原来指向列表项2指向了迷你列表向形成新的环

5.紧接着上面的代码末尾插入列表项2

//末尾插入列表项2TestList.pxIndex = TestList.pxIndex->pxNext;vListInsertEnd(&TestList ,&ListItem2);
printf("---------------------------末尾插入列表项ListItem2--------------------------\r\n");
printf("TestList->xListEnd->pxNext        %#x      \r\n",(int)(TestList.xListEnd.pxNext));
printf("ListItem1->pxNext                %#x               \r\n",(int)(ListItem1.pxNext));
printf("ListItem2->pxNext                %#x               \r\n",(int)(ListItem2.pxNext));
printf("ListItem3->pxNext                %#x               \r\n",(int)(ListItem3.pxNext));printf("-------------------------------前后连接分割线--------------------------------\r\n");
printf("TestList->xListEnd->pxPrevious    %#x   \r\n",(int)(TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious             %#x           \r\n",(int)(ListItem1.pxPrevious));
printf("ListItem2->pxPrevious             %#x           \r\n",(int)(ListItem2.pxPrevious));
printf("ListItem3->pxPrevious             %#x           \r\n",(int)(ListItem3.pxPrevious));
printf("-------------------------------结束-----------------------------------------\r\n");

用串口打印结果:

这时List的pxIdex指向了ListItem1,就是TestList.pxIndex = TestList.pxIndex->pxNext;这时ListItem1指向ListItem3,ListItem3指向迷你列表项,迷你列表项指向ListItem2,ListItem2指向ListItem1,形成环


http://www.mrgr.cn/news/97146.html

相关文章:

  • 蓝桥杯 小明的背包1 小兰的神秘礼物 01背包问题 模板 C++
  • [GN] Python3基本数据类型 -- 与C的差异
  • 7.训练篇5-毕设
  • Koordinator-NodeInfoCollector
  • 优选算法的妙思之流:分治——快排专题
  • Leetcode 169 -- 分治 | 摩尔投票法
  • Tradingview 策略分享 - SSL 混合和 CE 交易策略
  • MySQL学习笔记(一)——MySQL下载安装配置
  • C语言:数据的存储
  • 01背包问题:详细解释为什么重量维度必须从大到小遍历。
  • 消息队列之-Kafka
  • AI 数理逻辑基础之统计学基本原理(上)
  • Leetcode 127 -- 哈希表
  • 【嵌入式-stm32电位器控制以及旋转编码器控制LED亮暗】
  • WSL使用经验
  • 第三季:挪威
  • RocketMQ 中的 ProducerManager 组件剖析
  • Leetcode 857 -- 贪心 | 数学
  • OrangePi5Plus开发板不能正确识别USB 3.0 设备 (绿联HUB和Camera)
  • 指令补充+样式绑定+计算属性+监听器