FreeRTOS列表与列表项操作
jiang_2018 人气:0
前言
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); }
加载全部内容