freeRTOS链表学习笔记
链表是RTOS的核心之一,链表的作用主要服务于RTOS的任务之间的调度。任务的唤醒和休眠、任务的调度等都基于链表实现。阅读了freeRTOS链表的源码后,决定梳理一遍链表相关的源码,用于加深对链表的理解。其中对源码进行了一些删减,方便理解理解和阅读。文中的代码重新书写了一遍,可能和源码有些不一样。
1 头文件
头文件其中只涉及3个结构体,其中struct xMiniLIST_ITEM 是struct xLIST_ITEM 的简化版,则实际上只涉及2个结构体。
struct xLIST_ITEM
{
TickType_t xItemValue; /* 项目的值 用于链表的排序 */
struct xLIST_ITEM *pxNext; /* 双向链表指针 */
struct xLIST_ITEM *pxPrevious;
void* pvOwner; /* 链表下 所挂载的 内容 例如 TCB结构体。 */
void* pvContainer; /* 记录 位于哪个 链表 */
};
typedef struct xLIST
{
UBaseType_t uxNumberOfItems; /* 记录链表中挂在了多少项 */
ListItem_t* pxIndex; /* 记录当前链表正在操作那一项 */
MiniListItem_t xListEnd; /* 记录链表头尾指针 方便遍历 */
}List_t;
全部源码
#ifndef _LIST_H
#define _LIST_H
#define TickType_t unsigned int
#define UBaseType_t unsigned int
#define portMAX_DELAY 0xFFFFFFFF
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;
/*
为了节约内存 简化了 struct xLIST_ITEM 结构体 少了8个字节。
*/
struct xMiniLIST_ITEM
{
TickType_t xItemValue;
struct xLIST_ITEM *pxNext;
struct xLIST_ITEM *pxPrevious;
};
typedef struct xMiniLIST_ITEM MiniListItem_t;
typedef struct xLIST
{
UBaseType_t uxNumberOfItems; /* 记录链表中挂在了多少项 */
ListItem_t* pxIndex; /* 记录当前链表正在操作那一项 */
MiniListItem_t xListEnd; /* 记录链表头尾指针 方便遍历 */
}List_t;
void xListInitialiseItem(ListItem_t* const pxItem);
void xListInitialise(List_t* const pxList);
void xListInsertEnd(List_t* const pxList, ListItem_t*const pxNewListItem);
void xListInsert(List_t* const pxList, ListItem_t* const pxNewListItem);
void uxListRemove(ListItem_t* const pxItemToRemove);
2 C文件
C文件中具体涉及操作也不是很多,主要有初始化、插入和删除操作。其中不太好理解的为xListInsertEnd 和 xListInsert ,这里需要结合RTOS的设计思想(实时性),注释中做了说明。
#include <stdio.h>
#include "list.h"
/*
初始化一个链表项
*/
void xListInitialiseItem(ListItem_t* const pxItem)
{
/*
确保项目 没有 位于任何链表下
*/
pxItem->pvContainer = NULL;
}
/*
初始化一个链表
*/
void xListInitialise(List_t* const pxList)
{
/*
链表的偏移量 指向自己
*/
pxList->pxIndex = (ListItem_t* )pxList->xListEnd;
/*
此时链表项 数量为0
*/
pxList->uxNumberOfItems = 0;
/*
链表的链表项的项目值 为最大 这样排序的化 始终位于链表最后。
*/
pxList->xListEnd.xItemValue = portMAX_DELAY;
/*
初始化时,链表的链表项 的 前后指针 都指向自己的链表项。
*/
pxList->xListEnd.pxNext = (ListItem_t*)pxList->xListEnd;
pxList->xListEnd.pxPrevious = (ListItem_t*)pxList->xListEnd;
}
/*
在链表的最后插入新的一项。
这里的最后,不是指的链表的最后一项。而是指链表最后能遍历到的一项。
例如:
当前链表中有 Item1 Item2 Item3 其中pxIndex指向Item2,此时插入到
Item2的前面 Item1的后面,这样保证了最新插入的 最后执行。
场景:
相同优先的链表中,先插入先执行,后插入的后执行。
保证了各个任务之间的“公平性”。
*/
void xListInsertEnd(List_t* const pxList, ListItem_t* const pxNewListItem)
{
/*
找到 pxList 链表 的偏移量
*/
ListItem_t* pxIndex = pxList->pxIndex;
/*
新插入的项 下一项 指向pxIndex,前一项指向 pxIndex 的前一项。
pxIndex 的前面一项的下一项 指向 新插入的一项。前一项指向新插入的一项。
*/
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/*
插入一项后,链表中的项目数量 加 1
*/
pxList->uxNumberOfItems++;
/*
记录 新插入的一项指向 属于这个链表。
*/
pxNewListItem->pvContainer = pxList;
}
/*
按项目的值 从小到大排序 插入到链表中,如果值相同,则插入到后面。
场景:
在延时的链表中,项目值等于项目的 任务 延时的时间,延时时间久的最后执行,
则放在最后面。
*/
void xListInsert(List_t* const pxList, ListItem_t* const pxNewListItem)
{
ListItem_t* pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
if (xValueOfInsertion == portMAX_DELAY)
{
xValueOfInsertion = pxList->xListEnd.xItemValue;
}
else
{
/*
遍历找到 比xValueOfInsertion 大的项目。
如果项目存在和当前插入的值相等的项目,则需要插入到该项目的后一项。
pxIterator->pxNext->xItemValue <= xValueOfInsertion
*/
for (pxIterator = (ListItem_t*)&pxList->xListEnd;
pxIterator->pxNext->xItemValue <= xValueOfInsertion;
pxIterator = pxIterator->pxNext)
{
}
}
/*
把pxNewListItem 插入到pxIterator的后面
*/
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxList->uxNumberOfItems++;
pxNewListItem->pvContainer = (void*)pxList;
}
/*
从链表中的 某一项 删除
*/
UBaseType_t int uxListRemove(ListItem_t* const pxItemToRemove)
{
/*
确定删除的项目属于 哪个链表。
*/
xLIST * const pxList = pxItemToRemove->pvContainer;
/*
从链表中移除 pxItemToRemove
*/
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
/*
判断当前链表的偏移是否等于目前删除的项目
如果等于 则偏移量 移动到上次的偏移的位置。
*/
if (pxList->pxIndex == pxItemToRemove)
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
/*
清除删除项的链表记录信息。
*/
pxItemToRemove->pvContainer = NULL;
/*
链表中的项目减1
*/
pxList->uxNumberOfItems--;
return pxList->uxNumberOfItems;
}
```c
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in. Obtain the list from the list
* item. */
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/* Make sure the index is left pointing to a valid item. */
if( pxList->pxIndex == pxItemToRemove)
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
/*
清除删除项的链表记录信息。
*/
pxItemToRemove->pvContainer = NULL;
/*
链表中的项目减1
*/
pxList->uxNumberOfItems--;
return pxList->uxNumberOfItems;
}
本文深入探讨了FreeRTOS操作系统中的链表实现原理及其在任务调度中的应用。详细介绍了链表结构体定义、初始化过程以及插入、删除等核心操作的具体实现方式。
827

被折叠的 条评论
为什么被折叠?



