FreeRTOS列表与列表项
程序员文章站
2024-02-22 19:01:48
...
前言
FreeRTOS列表与列表项其实就是链表和节点,在list.c
和list.h
实现
列表项数据结构
//列表项数据结构
typedef struct xLIST_ITEM
{
TickType_t xItemValue; //辅助值,用作节点做顺序排序
struct xLIST_ITEM * pxNext;//后继指针
struct xLIST_ITEM * pxPrevious;//前驱指针
void * pvOwner; //指向拥有该列表项的内核对象,通常是TCB
void * pvContainer; //指向该列表项所在的列表
}ListItem_t;
列表项初始化
void vListInitialiseItem(ListItem_t * const pxItem)
{
//初始化该列表项所在列表指针指向NULL,表示还没插入任何列表
pxItem->pvContainer = NULL;
}
列表数据结构
typedef struct xLIST
{
UBaseType_t uxNumberOfItems; //指示这条列表上有多少个列表项
ListItem_t * pxIndex; //列表项索引指针
MiniListItem_t xListEnd; //列表最后一个列表项
}List_t;
其中MiniListItem_t
数据结构如下
typedef struct xMINI_LIST_ITEM
{
TickType_t xItemValue;//辅助值,用作节点做顺序排序
struct xLIST_ITEM * pxNext;//后继指针
struct xLIST_ITEM * pxPrevious;//前驱指针
}MiniListItem_t;
可以看到是列表项数据结构去掉了pvOwner
和pvContainer
成员
列表初始化
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);
//表示此时列表中有0个列表项
pxList->uxNumberOfItems = (UBaseType_t)0U;
}
如下图
将列表项插入列表尾部
void vListInsertEnd(List_t * const pxList,ListItem_t * const pxNewListItem)
{
//取列表项索引指针,此时该指针指向最后一个节点
ListItem_t * const pxIndex = pxList->pxIndex;
//新插入的列表项前驱指针指向最后一个节点
pxNewListItem->pxNext = pxIndex;
//新插入的列表项的后继指针也指向最后一个节点
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
//列表的最后一个节点的后继指针指向新插入的列表项
pxNewListItem->pxPrevious->pxNext = pxNewListItem;
//列表的最后一个节点的前驱指针也指向新插入的列表项
pxIndex->pxPrevious = pxNewListItem;
//新插入的列表项是输入该列表的
pxNewListItem->pvContainer = (void*) pxList;
//该列表中列表项数目+1
(pxList->uxNumberOfItems)++;
}
如下
将列表项按照升序排列插入到列表
假如向现有的2个列表项序辅助值分别是 1 和 3的列表插入辅助值是2个列表项
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)
{
}
}
//对于下图此时pxIterator指向List_item1
//此时pxIterator->pxNext是List_item3地址
pxNewListItem->pxNext = pxIterator->pxNext;//1
//pxNewListItem->pxNext->pxPrevious是item3的前驱指针指向新列表项item2
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
//新列表项item2的前驱指针指向pxIterator即item1
pxNewListItem->pxPrevious = pxIterator;
//pxIterator即item1的后继指向新列表项item2
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pvContainer = (void*) pxList;
(pxList->uxNumberOfItems)++;
}
如图,注意2、3步的指针箭头,野火的pdf画的有误
将列表项从列表删除
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;
//
if(pxList->pxIndex == pxItemToRemove)
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
//该列表项所有者置空
pxItemToRemove->pvContainer = NULL;
(pxList->uxNumberOfItems)--;
return pxList->uxNumberOfItems;
}
下面是测试代码即仿真结果
List_t List_Test;
ListItem_t List_Item1;
ListItem_t List_Item2;
ListItem_t List_Item3;
int main(void)
{
//初始化列表
vListInitialise(&List_Test);
//初始化列表项
vListInitialiseItem(&List_Item1);
List_Item1.xItemValue = 1;
vListInitialiseItem(&List_Item2);
List_Item2.xItemValue = 2;
vListInitialiseItem(&List_Item3);
List_Item3.xItemValue = 3;
vListInsert(&List_Test,&List_Item1);
vListInsert(&List_Test,&List_Item3);
vListInsert(&List_Test,&List_Item2);
while(1);
}
上一篇: java实现图片任意角度旋转