目录
列表和列表项的简介
列表
列表项
迷你列表项
列表和列表项的关系
列表相关API函数介绍
初始化列表vListInitialise函数详解
列表项的初始化函数vListInitialiseItem函数
列表项的插入vListInsert函数
列表项末尾插入vListInsertEnd函数
列表项的删除函数uxListRemove函数
列表和列表项的简介
列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪 FreeRTOS中的任务。列表项就是存放在列表中的项目示意图:
列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向环形链表。
列表的特点:列表项间的地址非连续的,是人为的连接到一起的。列表项的数目是由后期添加的个数决定的,随时可以改变。可以理解为列表就是就绪列表,列表项里面存的是某个任务就绪。
数组的特点:数组成员地址是连续的,数组在最初确定了成员数量后期无法改变。
在OS中任务的数量是不确定的,并且任务状态是会发生改变的,所以非常适用列表(链表)这种数据结构。
列表
有关于列表的东西均在文件list.c和list.h中,首先我们先看下在list.h中的,列表相关结构体:
1.在该结构体中,包含了两个宏校验值,这两个宏是确定的已知常量,FreeRTOS通过检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏,该功能一般用于调试,默认是不开启的。
2.成员uxNumberOfltems,用于记录列表中列表项的个数(不包含xListEnd)。
3.成员pxindex用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项。
4.成员变量xListEnd 是一个迷你列表项,排在最末尾
列表项
列表项是列表中用于存放数据的地方,在list.h文件中,有列表项的相关结构体定义:
1.同样2个用于检测列表项的数据完整性不用管,是调试时候用。
2.成员变量xltemValue为列表项的值,这个值多用于按升序对列表中的列表项进行排序。
3.成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项。
4.成员变量pxOwner用于指向包含列表项的对象(通常是任务控制块)。
5.成员变量pxContainer用于指向列表项所在列表。
迷你列表项
迷你列表项也是列表项,但迷你列表项仅用于标记列表的末尾和挂载其他插入列表中的列表项。
1.用于检测数据完整性同样是调试用。
2.成员变量xltemValue为列表项的值,这个值多用于按升序对列表中的列表项进行排序。
3.成员变量 pxNext和pxPrevious分别用于指向列表中列表项的下一个列表项和上一个列表项。
4.迷你列表项只用于标记列表的末尾和挂载其他插入列表中的列表项,因此不需要成员变量pxOwner和pxContainer,以节省内存开销。
列表和列表项的关系
列表初始状态,以及即将插入的两个列表项如下:
列表成员:
初始化时数量是0,索引指向末尾列表项(迷你列表)前和后都指向自己:
插入列表项1,数值是10会插入到末尾列表项前面,又因为是双向的所以互指,此时列表的数量uxNumberOfltems = 1:
插入列表项2也是同理,数值是20会插入到末尾列表项前面列表项1后面,此时列表的数量uxNumberOfltems = 2:
最后的结果就是如下图所示:
列表相关API函数介绍
初始化列表vListInitialise函数详解
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
/*初始化时列表中只有末尾列表项因此pxIndex指向末尾列表项*/
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
/*末尾列表项数值赋值为最大,用于列表升序排序*/
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
/*列表中只有末尾列表项所以前和后都指向自己*/
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
/*末尾列表项不算在列表项里面,列表数量值为0*/
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
/*检查数据的完整性的校验*/
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
列表项的初始化函数vListInitialiseItem函数
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* Make sure the list item is not recorded as being on a list. */
/*初始化时,列表项所在列表设为空*/
pxItem->pvContainer = NULL;
/* Write known values into the list item if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
/*初始化用于检测列表项数据完整性的校验值*/
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
列表项的插入vListInsert函数
此函数用于将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
/*获取列表项的数值依据数值升序排列*/
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
/* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */
/*检查参数是否正确*/
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert the new list item into the list, sorted in xItemValue order.
If the list already contains a list item with the same item value then the
new list item should be placed after it. This ensures that TCB's which are
stored in ready lists (all of which have the same xItemValue value) get a
share of the CPU. However, if the xItemValue is the same as the back marker
the iteration loop below will not end. Therefore the value is checked
first, and the algorithm slightly modified if necessary. */
/*判断数值是不是最大值*/
if( xValueOfInsertion == portMAX_DELAY )
{
/*插入的位置为列表xListEnd前面*/
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
/* *** NOTE ***********************************************************
If you find your application is crashing here then likely causes are
listed below. In addition see http://www.freertos.org/FAQHelp.html for
more tips, and ensure configASSERT() is defined!
http://www.freertos.org/a00110.html#configASSERT
1) Stack overflow -
see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
2) Incorrect interrupt priority assignment, especially on Cortex-M
parts where numerically high priority values denote low actual
interrupt priorities, which can seem counter intuitive. See
http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
http://www.freertos.org/a00110.html
3) Calling an API function from within a critical section or when
the scheduler is suspended, or calling an API function that does
not end in "FromISR" from an interrupt.
4) Using a queue or semaphore before it has been initialised or
before the scheduler has been started (are interrupts firing
before vTaskStartScheduler() has been called?).
**********************************************************************/
/*遍历列表中的列表项,找到插入的位置*/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
pxIterator->pxNext->xItemValue <= xValueOfInsertion;
pxIterator = pxIterator->pxNext )
/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
{
/* There is nothing to do here, just iterating to the wanted
insertion position. */
}
}
/*将待插入的列表项插入指定位置,双向链表的插入*/
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the
item later. */
/*更新待插入列表项所在列表*/
pxNewListItem->pvContainer = ( void * ) pxList;
/*更新列表中列表项的数量*/
( pxList->uxNumberOfItems )++;
}
列表项末尾插入vListInsertEnd函数
此函数用于将待插入列表的列表项插入到列表pxindex 指针指向的列表项前面,是一种无序的插入方法
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;
/* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */
/*检查参数是否正确*/
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert a new list item into pxList, but rather than sort the list,
makes the new list item the last item to be removed by a call to
listGET_OWNER_OF_NEXT_ENTRY(). */
/*更新待插入列表项的指针成员变量*/
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
/* Only used during decision coverage testing. */
/*调试用*/
mtCOVERAGE_TEST_DELAY();
/*更新列表中原本列表项的指针成员变量*/
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* Remember which list the item is in. */
/*更新待插入列表项的所在列表成员变量*/
pxNewListItem->pvContainer = ( void * ) pxList;
/* 更新列表中列表项的数量*/
( pxList->uxNumberOfItems )++;
}
列表项的删除函数uxListRemove函数
此函数用于将列表项从列表项所在列表中移除
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 = ( List_t * ) pxItemToRemove->pvContainer;
/*从列表中移除列表项*/
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. */
/*如果 pxindex 正指向待移除的列表项*/
if( pxList->pxIndex == pxItemToRemove )
{
/*pxIndex 指向上一个列表项*/
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
/*为实现函数*/
mtCOVERAGE_TEST_MARKER();
}
/*将待移除的列表项的所在列表指针清空*/
pxItemToRemove->pvContainer = NULL;
/*更新列表中列表项的数量*/
( pxList->uxNumberOfItems )--;
/*返回移除后的列表中列表项的数量*/
return pxList->uxNumberOfItems;
}