FreeRTOS的列表和列表项

列表和列表项作为FreeRTOS源码的基本数据结构,相当于数据结构中的循环双链表。

1.定义:关于这部分的数据主要有三种结构(列表、列表项、迷你列表项)

列表

typedef struct xList
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE        //检查列表的完整性,是宏定义
    configLIST_VOLATILE UBaseType_t    uxNumberOfItems;    //记录列表中列表项的数量
    ListItem_t* configLIST_VOLATILE    pxIndex;            //记录当前列表项的索引号,用于遍历列表
    MiniListItem_t                     xListEnd;            //列表中最后一个列表项
    listSECOND_LIST_INTEGRTIY_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;        //列表项的归属,一般指向任务控制块
    void*    configLIST_VOLATILE                    pvContainer;    //记录链表项属于哪个列表,比如空闲列表/就绪列表
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE    //检查列表项的完整性
};

typedef struct xLIST_ITEM    ListItem_t;

迷你列表项

struct xMINI_LIST_ITEM
{
    listFITRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
    configLIST_VOLATILE TickType_t            xItemValue;
    struct xLIST_ITEM*    configLIST_VOLATILE pxNext;
    struct xLIST_ITEM*    configLIST_VOLATILE pxPrevious;
};

typedef struct xMINI_LIST_ITEM    MiniListItem_t;

2、基本操作:

一般链表的操作包括链表的创建(初始化)、插入、删除、查找。

列表和列表项初始化:

//列表初始化
void vListInitialise(List_t* const pxList)
{
    pxList->pxIndex = (ListItem_t *) &(pxList->xListEnd);
    pxList->xListEnd.xItemValue = portMAX_DELAY;    //portMAX_DELAY是个宏定义,STM32中式0xffffffffUL,表示列表数量的最大值
    pxList->xListEnd.pxNext = (ListItem_t *) &(pxList->xListEnd);    //列表项的下一项指向自身
    pxList->xListEnd.pxPrevious = (ListItem_t *) &(pxList->xListEnd);
    pxList->uxNumberOfItems = (UBaseType_t) 0U;    //当前列表中的列表项为0,自身不算
    //如果configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES被置为1,执行下面语句
    list_SET_LIST_INTEGRITY_CHECK_1_VALUE(pxList);
    list_SET_LIST_INTEGTITY_CHECK_2_VALUE(pxList);    
}

//列表项初始化
void vListInitialiseItem(ListItem_t* const pxItem)
{
    pxItem->pvContainer = NULL;
    
    listSET_FIRST_LIST_ITEM_ INTEGRITY_CHECK_VALUE(pxItem);
    listSET_FIRST_LIST_ITEM_INTERITY_CHECK_VALUE(pxItem);
}

列表项插入:

/*功能:向列表中插入列表项
 *参数:pxList(列表项要插入的列表) pxNewListItem(要插入的列表项)
 *返回值:无
*/
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;    //将新节点的后一个节点指向原来pxIterator的后一个节点
    pxNewListItem->pxNext->pxPrevious = pxNewListItem;    //将新节点的后一个节点的前一个指针指向新节点
    pxNewListItem->pxPrevious = pxIterator;         //将新节点的上一个节点指向原来的节点
    pxIterator->pxNext = pxNewListItem;            //将原来节点的下一个节点指针指向新节点
    
    pxNewListItem->pvContainer = (void*) pxList;    //新节点属于的队列
    (pxList->uxNumberOfItems)++;                    //节点数加一

}

列表末尾插入:

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;                //将新列表项的下一项指向列表头pxIndex
    pxNewListItem->previous = pxIndex->pxPrevious;
    
    mtCOVERAGE_TEST_DELAY();
    
    pxIndex->pxPrevious->pxNext = pxNewListItem;    //将列表尾指向新列表
    pxIndex->pxPrevious = pxNewListItem;            //将原来的头列表的上个节点指向新列表
    
    pxNewListItem->pvContainer = (void *)pxList;

    (pxList->uxNumberOfItems)++;
}

列表项的删除操作:

UBaseType_t uxListRemove(ListItem_t* const pxItemToRemove)
{
    List_t* const pxList = (List_t*)pxItemToRemove->pvContainer;    //确定所在列表
    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    pxItemToRemove->pxPrevious->next = pxItemToRemove->pxNext;

    mCOVERAGE_TEST_DELAY();
    
    if(pxList->pxIndex == pxItemToRemove)    //如果删除的是表头
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    pxItemToRemove->pvContainer = NULL;
    (pxList->uxNumberOfItems)--;

    return pxList->uxNumberOfItems;
}

列表的遍历:listGET_OWNER_OF_NEXT_ENTRY(pxTCB, pxList)

该函数是利用列表中pxIndex项来遍历整个列表,大家可以试试。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS中,任务、队列、信号量等都是以列表的形式存储的,因此,列表的遍历是非常常见的操作。FreeRTOS提供了一些API来遍历不同类型的列表。 以任务列表为例,FreeRTOS提供了以下API来遍历任务列表: 1. `vTaskList()`:此API将任务列表的详细信息打印到标准输出。 2. `vTaskGetRunTimeStats()`:此API将任务列表中每个任务的运行时间、CPU使用率等信息打印到标准输出。 如果你需要在代码中遍历任务列表,可以使用以下API: 1. `vTaskSuspendAll()`:此API将所有任务暂停,以便安全地遍历任务列表。 2. `xTaskGetNextTask()`:此API返回一个指向下一个任务控制块的指针。 3. `xTaskResumeAll()`:此API将所有任务恢复,以便它们可以继续执行。 以下是一个示例代码,展示了如何使用上述API来遍历任务列表: ``` void vTaskListAll(void) { TaskStatus_t *pxTaskStatusArray; volatile UBaseType_t uxArraySize, x; // 获取任务数量 uxArraySize = uxTaskGetNumberOfTasks(); // 分配存储任务状态信息的内存 pxTaskStatusArray = pvPortMalloc(sizeof(TaskStatus_t) * uxArraySize); // 获取任务状态信息 uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, NULL); // 打印任务状态信息 printf("TaskName\t\tPriority\tStatus\t\tStackHighWaterMark\n"); for(x = 0; x < uxArraySize; x++) { printf("%s\t\t%d\t\t%s\t\t%d\n", pxTaskStatusArray[x].pcTaskName, pxTaskStatusArray[x].uxCurrentPriority, pxTaskStatusArray[x].eCurrentState == eRunning ? "Running" : pxTaskStatusArray[x].eCurrentState == eReady ? "Ready" : pxTaskStatusArray[x].eCurrentState == eBlocked ? "Blocked" : "Unknown", pxTaskStatusArray[x].usStackHighWaterMark); } // 释放存储任务状态信息的内存 vPortFree(pxTaskStatusArray); } ``` 这个函数将列出所有任务的名称、优先级、状态和堆栈高水位标记。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值