FreeRTOS列表与列表项及其操作

本文介绍FreeRTOS中的列表与列表项,及列表项的插入,删除等操作,仅作参考。

1.列表与列表项

列表是FreeRTOS中的一种数据结构,类似于C语言中的双向环形链表,用于跟踪FreeRTOS中的任务,记录任务的当前状态或事件,比如就绪列表,任务创建完成时就会添加至就绪列表,等待调度器调用。

列表结构体如下:

typedef struct xLIST            //列表结构体
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE         //用于校验
    volatile UBaseType_t uxNumberOfItems;        //列表中列表项数量
    ListItem_t * configLIST_VOLATILE pxIndex;    //指向某个列表项,用于遍历
    MiniListItem_t xListEnd;                     //末尾列表项
    listSECOND_LIST_INTEGRITY_CHECK_VALUE       //用于校验
} List_t;

列表项是存放于列表中的数据,如果列表相当于数组,列表项就相当于数组中的元素,如果列表相当于链表,列表项就相当于链表的节点。

列表项结构体如下:

struct xLIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE            //校验值      
    configLIST_VOLATILE TickType_t xItemValue;           //列表项的值,用于升序排序  
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;      //指向下一个列表项的指针
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  //指向前一个列表项的指针
    void * pvOwner;                                      //列表项的拥有者,也就是任务控制块
    struct xLIST * configLIST_VOLATILE pxContainer;      //此列表项所属的列表
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          //校验值    
};

 迷你列表项:存放于列表的最后一项,只有列表项值,前指针和后指针。

struct xMINI_LIST_ITEM        //迷你列表项
    {
        listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE         //校验值,无需理会
        configLIST_VOLATILE TickType_t xItemValue;        //列表项值,用于列表项升序排序
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;   //指向前一个列表项的指针
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
        //指向后一个列表项的指针,因为它是最后一项,所以这个指向第一项,环形列表
    };

2.列表的操作

(1)列表与列表项的初始化

void vListInitialise( List_t * const pxList )//列表初始化函数,参数为待初始化的列表
{
    pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );//将索引值指向末尾列表项

    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );//校验

    pxList->xListEnd.xItemValue = portMAX_DELAY;//将末尾列表项的值设置为最大
    //末尾列表项的后向指针指向自己
    pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );   
    //末尾列表项的前向指针指向自己  
    pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); 

    pxList->uxNumberOfItems = ( UBaseType_t ) 0U;//列表项的数量初始化为0,末尾列表项不算

    listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );//校验
    listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );//校验
}
void vListInitialiseItem( ListItem_t * const pxItem )//列表项初始化,参数为待初始化的列表项
{
    
    pxItem->pxContainer = NULL;//将列表项的所属列表设置为NULL

    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );//校验
    listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );//校验
}

(2)列表的升序插入

void vListInsert( List_t * const pxList,        //升序插入函数,第一个参数为要插入的列表
                  ListItem_t * const pxNewListItem )//第二个参数为要插入的列表项
{
    ListItem_t * pxIterator;        //定义一个中间变量列表项指针
    //获取要插入的列表项的值,以此确定要插入的位置
    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

    listTEST_LIST_INTEGRITY( pxList );//检验参数
    listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );//检验参数

    if( xValueOfInsertion == portMAX_DELAY )//如果列表项值为最大值
    {
        pxIterator = pxList->xListEnd.pxPrevious;//则插入末尾列表项的前面
    }
    else//如果不是最大值
    {
        for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->            
            xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 
        {
            //这个循环就在找列表项值大于前一项而小于后一项的位置
            //具体是将中间变量=末尾列表项,如要插入的列表项值大于末尾列表项的下一项的列表项值,也就是第一项,则中间变量=下一项,由此循环,直到找到列表项值大于要插入的列表项值为止
        }
    }
    //找到的这个中间变量就是要插入的位置,以下操作就是将新列表项插入到找到的位置后面
    pxNewListItem->pxNext = pxIterator->pxNext;    
    pxNewListItem->pxNext->pxPrevious = pxNewListItem;
    pxNewListItem->pxPrevious = pxIterator;
    pxIterator->pxNext = pxNewListItem;

    pxNewListItem->pxContainer = pxList;//将新插入项的所属列表更新为要插入的列表

    ( pxList->uxNumberOfItems )++;//列表项数量++
}

(3)列表的尾部插入:其实是插入到列表索引值的前面,初始化时这个索引值指向末尾列表项

void vListInsertEnd( List_t * const pxList,        //第一个参数为要插入到的列表
                     ListItem_t * const pxNewListItem )//第二个参数为要插入的列表项
{
    ListItem_t * const pxIndex = pxList->pxIndex;    //获取列表的索引值


    listTEST_LIST_INTEGRITY( pxList );//检验参数
    listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );//检验参数

    //以下操作将新列表项插入到索引值前面,因为初始化时索引值指向末尾列表项,
    //所以也就是插到末尾列表项前面
    pxNewListItem->pxNext = pxIndex;
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;
    mtCOVERAGE_TEST_DELAY();
    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;

    pxNewListItem->pxContainer = pxList;//更新列表项所属列表

    ( pxList->uxNumberOfItems )++;//列表项数量++
}

(4)列表项的删除

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )//列表项删除,参数待删除列表项
{

    List_t * const pxList = pxItemToRemove->pxContainer;//先获取该列表项所属列表

    //以下两句就是将该列表项的前面一项指向其后面一项,后面一项指向其前面一项
    //这样该列表项从列表中脱离出去了
    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

    mtCOVERAGE_TEST_DELAY();

    if( pxList->pxIndex == pxItemToRemove )//如果列表的索引值指向要删除的该列表项
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;//则将索引值指向其前面一项
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    pxItemToRemove->pxContainer = NULL;//更新该列表项所属列表为空
    ( pxList->uxNumberOfItems )--;//列表项数量--

    return pxList->uxNumberOfItems;//返回剩余列表项数量
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值