FreeRTOS学习——链表list

news2024/12/26 3:34:47

FreeRTOS学习——链表(列表)list,仅用于记录自己阅读与学习源码

FreeRTOS Kernel V10.5.1

参考大佬的好文章:
freertos内核原理 Day1(链表)
FreeRTOS-链表的源码解析

*list_t只能存储指向list_item_t的指针。每个list_item_t都包含一个数值(xItemValue)。大多数时候,列表是按项目值升序排列的。

*创建的列表已包含一个列表项。此项的值是可以存储的最大值,因此它始终位于列表的末尾,并充当标记。列表成员pxHead始终指向此标记,即使它位于列表的末尾。这是因为尾部包含一个返回指针,指向列表的真正头部。

*除了它的值外,每个列表项还包含一个指向列表中下一个项的指针(pxNext)、一个指向它所在列表的指针(pxContainer)和一个指向包含它的对象的指针。为了提高列表操作的效率,包含了后两个指针。包含列表项的对象和列表项本身之间实际上存在双向链接。

链表结构体

关于链表的结构体,有三个,分别是

1. 节点结构体
2. 尾节点结构体(mini节点)
3. 链表结构体

可以看大佬的博客freertos内核原理 Day1(链表),非常清晰

节点结构体 ListItem_t

/*
 * 列表可以包含的唯一对象类型的定义
 */
struct xLIST_ITEM
{
    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*< 链表节点完整性检查值1 */
    configLIST_VOLATILE TickType_t xItemValue;          /*< 链表节点值,用于阻塞升序排序 */
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;     /*< 指向链表中的下一个节点 */
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< 指向链表中的上一个节点 */
    void * pvOwner;                                     /*< 指向拥有该链表节点的对象 (一般是TCB) . */
    struct xLIST * configLIST_VOLATILE pxContainer;     /*< 指向节点所在的链表. */
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*< 链表节点完整性检查值2. */
};
typedef struct xLIST_ITEM ListItem_t;

若宏configLIST_VOLATILE定义为空,且若完整性检查宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES也为0的话(见下面关于链表宏部分),那么这个链表节点结构体其实就长这个样子,一下子干净多了。

struct xLIST_ITEM
{
    TickType_t xItemValue;          /*< 链表节点值,用于阻塞升序排序 */
    struct xLIST_ITEM * pxNext;     /*< 指向链表中的下一个节点 */
    struct xLIST_ITEM * pxPrevious; /*< 指向链表中的上一个节点 */
    void * pvOwner;                 /*< 指向拥有该链表节点的对象 (一般是TCB) . */
    struct xLIST * pxContainer;     /*< 指向节点所在的链表. */
};
typedef struct xLIST_ITEM ListItem_t;

链表节点值TickType_t xItemValue;为什么是TickType_t 类型呢,阻塞时间就是多少个TickType_t ,这个值用于插入延迟列表时,将节点从低到高的排列,阻塞时间段的在最前面,只要前面的没有唤醒,那么后面的也一定在阻塞,因为是升序排列的。

尾节点结构体(mini节点) MiniListItem_t

#if ( configUSE_MINI_LIST_ITEM == 1 )
    struct xMINI_LIST_ITEM
    {
        listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< 链表节点完整性检查值1 */
        configLIST_VOLATILE TickType_t xItemValue;
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
    };
    typedef struct xMINI_LIST_ITEM MiniListItem_t;
#else
    typedef struct xLIST_ITEM      MiniListItem_t;
#endif

如果宏configUSE_MINI_LIST_ITEM 为1 ,则定义xMINI_LIST_ITEM 为MiniListItem_t,否则就把普通节点xLIST_ITEM定义为尾节点。

与普通节点相比,尾节点结构体少了pvOwner和pxContainer

链表结构体(根节点) List_t

/*
 * 调度器使用的队列类型的定义
 */
typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE      /*< 链表完整性检查值1 */
    volatile UBaseType_t uxNumberOfItems;
    ListItem_t * configLIST_VOLATILE pxIndex; /*< 索引指针,通过调用listGET_OWNER_OF_NEXT_ENTRY ()来遍历链表的指针 */
    MiniListItem_t xListEnd;                  /*< 尾节点拥有最大的xItemValue值. */
    listSECOND_LIST_INTEGRITY_CHECK_VALUE     /*< 链表完整性检查值2 */
} List_t;

注意,尾节点结构体MiniListItem_t 和链表结构体List_t并不是链表连接起来的,而是MiniListItem_t 是List_t的一部分,可以把List_t想象成一个大东西,而这个大东西 在链表的尾部,也可以说在头尾,因为是双向链表。List_t通过MiniListItem_t 链接起整个链表,只要获取了List_t,就能一节一节的获取整个链表,List_t也可以叫做根节点。

链表操作

初始化链表 vListInitialise

void vListInitialise( List_t * const pxList )
{
    /* 将索引指针指向尾节点 */
    pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*尾节点xListEnd使用mini节点结构体,节省RAM */
    /*给尾节点完整性检查值 赋值,尾节点只有一个完整性检查值 */
    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );

    /* 尾节点值为最大值0xffffffffUL,确保其为最后一个节点*/
    pxList->xListEnd.xItemValue = portMAX_DELAY;

    /* 当链表为空时,尾节点的前后指针指向尾节点自己 */
    pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );     
    pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); 

    /* 如果尾节点没有使用mini节点结构体,则初始化其pvOwner和pxContainer指针 */
    #if ( configUSE_MINI_LIST_ITEM == 0 )
    {
        pxList->xListEnd.pvOwner = NULL;
        pxList->xListEnd.pxContainer = NULL;
        listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( &( pxList->xListEnd ) );
    }
    #endif
    /*节点数量为0*/
    pxList->uxNumberOfItems = ( UBaseType_t ) 0U;

    /* 给链表完整性检查值 赋值 */
    listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
    listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
  1. 链表索引指针指向尾节点
  2. 尾节点值设为最大值,且前后指针都指向自己
  3. 节点数量为0

初始化链表节点 vListInitialiseItem

void vListInitialiseItem( ListItem_t * const pxItem )
{
    /* pxContainer指该节点属于哪个链表,初始值为NULL,确保该节点没有在任何链表中. */
    pxItem->pxContainer = NULL;

    /* 给节点完整性检查值 赋值. */
    listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
    listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}

链表尾部插入节点 vListInsertEnd

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 插入到 pxIndex 之前  */
    pxNewListItem->pxNext = pxIndex;
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;

    /* 覆盖率测试,不影响功能,仅用于覆盖率测试 */
    mtCOVERAGE_TEST_DELAY();

    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;

    /* 将节点的pxContainer指针指向链表 */
    pxNewListItem->pxContainer = pxList;

    /*链表节点数量加1*/
    ( pxList->uxNumberOfItems )++;
}
  1. 将新节点 pxNewListItem 插入到 pxIndex 之前
  2. 将节点的pxContainer指针指向链表
  3. 链表节点数量加1

链表插入节点 vListInsert

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 );

    /* 将新的列表项插入列表,按xItemValue顺序排序
     * 如果节点值是最大值,则插入到尾节点之前*/
    if( xValueOfInsertion == portMAX_DELAY )
    {
        pxIterator = pxList->xListEnd.pxPrevious;
    }
    else
    {
        /* *** NOTE ***********************************************************
        *  如果程序崩溃,可能原因如下:
        *
        *   1) 栈溢出
        *   2) 优先级分配错误
        *   3) 从关键部分或当调度程序暂停时调用API函数,或从中断调用不以“FromISR”结尾的API函数
        *   4) 在队列或信号量初始化之前 或 调度程序启动之前使用它(中断是在vTaskStartScheduler()被调用之前触发的吗?)
        *   5) 果FreeRTOS端口支持中断嵌套,则确保滴答中断的优先级等于或低于configMAX_SYSCALLINTERRUPT_priority
        **********************************************************************/

        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;

    /* 将新节点的pxContainer指针指向链表 */
    pxNewListItem->pxContainer = pxList;
    /*链表节点数量加1*/
    ( pxList->uxNumberOfItems )++;
}
  1. 确认要插入的位置,如果节点值是最大值,则插入到尾节点之前,否则遍历链表
  2. 插入新节点
  3. 将新节点的pxContainer指针指向链表
  4. 链表节点数量加1

从链表移除节点 uxListRemove

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();
    }
    /* 将节点的pxContainer指针指向NULL */
    pxItemToRemove->pxContainer = NULL;
    /*链表节点数量减 1*/
    ( pxList->uxNumberOfItems )--;

    /*返回链表中剩余节点数量*/
    return pxList->uxNumberOfItems;
}
  1. 将节点从链表中移除
  2. 将节点的pxContainer指针指向NULL
  3. 链表节点数量减 1并返回链表中剩余节点数量

链表宏

configLIST_VOLATILE

*列表结构成员是在中断内修改的,因此应该声明为volatile。然而,它们只能以功能原子的方式进行修改(在调度器挂起的关键部分内),并且要么通过引用传递到函数中,要么通过volatile变量进行索引。因此,在迄今为止测试的所有用例中,可以省略volatile限定符,以便在不影响功能行为的情况下提供适度的性能改进。IAR、ARM和GCC编译器在为最大优化设置相应编译器选项时生成的汇编指令已经过检查,并被认为符合预期。也就是说,随着编译器技术的进步,特别是如果使用了激进的跨模块优化(一个没有得到很大程度应用的用例),那么正确的优化就可能需要volatile限定符。预计编译器会删除基本代码,因为如果列表结构成员上没有volatile限定符,并且进行了积极的跨模块优化,编译器认为代码是不必要的,这将导致调度器完全和明显的失败。如果遇到这种情况,那么只需在FreeRTOSConfig.h中将configLIST_volatile定义为volatile,就可以将volatile限定符插入列表结构中的相关位置(如本注释块底部的示例所示)。如果未定义configLIST_VOLATILE,则下面的预处理器指令将完全#define configLIST_VOLATILE。

*要使用volatile列表结构成员,请在FreeRTOSConfig.h中添加以下行(不带引号):“#define configLIST_volatile volatile”

#ifndef configLIST_VOLATILE
    #define configLIST_VOLATILE
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */

简单点说就是在迄今为止测试的所有用例中,可以省略volatile。但是如果使用了激进的跨模块优化,就可能需要volatile限定符,那么就在FreeRTOSConfig.h中添加:“#define configLIST_volatile volatile”。

现在configLIST_VOLATILE是定义为空的,因为volatile可以省略。

configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES

可用于在列表结构中放置已知值的宏,然后检查已知值在应用程序执行过程中是否损坏。这些可能会捕获内存中被覆盖的列表数据结构。它们不会捕获因FreeRTOS配置或使用不正确而导致的数据错误
在这里插入图片描述
在FreeRTOS中,这段宏定义与列表数据完整性检查相关。具体来说,它们的作用是根据configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES宏的值决定是否启用数据完整性检查功能。
(默认为0,即不开启)

当configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES被设置为0时,这段代码通过定义一系列宏为空操作(即不执行任何操作),来关闭列表数据的完整性检查功能。这意味着在使用列表数据结构时,系统不会进行额外的完整性校验,这样可以降低运行时的开销,适用于对性能要求较高的场景。

这些宏的具体定义如下:

*listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE :列表节点完整检查值1
*listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE:列表节点完整检查值2。
这两个用于表示列表节点完整性检查的值,若不启用则为空。若启用了会在列表节点结构体中添加
TickType_t xListItemIntegrityValue1;
和TickType_t xListItemIntegrityValue2;

*listFIRST_LIST_INTEGRITY_CHECK_VALUE :列表完整检查值1
*listSECOND_LIST_INTEGRITY_CHECK_VALUE:列表完整检查值2
同上面两个值类似,用于表示整个列表的完整性检查值,同样不启用时为空。

*listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem):赋值列表节点完整性检查值1
*listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem):
它会赋值列表节点中的xListItemIntegrityValue为定义的值#define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL

*listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList) :赋值列表完整性检查值1
*listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList):
同上面两个值类似

*listTEST_LIST_ITEM_INTEGRITY(pxItem):用于测试列表节点的完整性
*listTEST_LIST_INTEGRITY(pxList):用于测试整个列表的完整性
上面的宏不是已经幅过值了吗,那么这两个宏就是检查上面的值有没有发生变化

总之,这些宏确保在不需要数据完整性检查时,代码的执行不会受影响,从而提高系统的性能。同时,若需要进行完整性检查(即configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为非零值),这些宏可以被重新定义,以执行必要的检查逻辑。这样的设计使得FreeRTOS能够灵活地在不同的应用场景中进行配置。

listGET_OWNER_OF_NEXT_ENTRY

/*
 * 链表成员pxIndex用于遍历列表
 * 调用listGET_OWNER_OF_NEXT_ENTRY会将pxIndex递增到列表中的下一个节点,并返回该节点的拥有者pxOwner(一般是TCB)。
 * 因此,通过多次调用此函数,可以遍历列表中包含的每个项目。
 * 列表项的pxOwner参数是指向拥有该列表项的对象的指针。在调度器中,这通常是一个任务控制块。
 */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \
    {                                                                                          \
        List_t * const pxConstList = ( pxList );                                               \
        /* 链表索引pxIndex指向下一个节点*/               \
        /* 确保不返回尾节点  */                         \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
        {                                                                                      \
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \
        }                                                                                      \
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \
    }

listREMOVE_ITEM

/*
 * 删除节点
 * 不返回值的uxListRemove()的版本。通过内联对xTaskIncrementTick()进行了轻微优化
 */
#define listREMOVE_ITEM( pxItemToRemove ) \
    {                                     \
        /* 获取节点所在的链表 */                                                              \
        List_t * const pxList = ( pxItemToRemove )->pxContainer;                 \
                                                                                 \
        ( pxItemToRemove )->pxNext->pxPrevious = ( pxItemToRemove )->pxPrevious; \
        ( pxItemToRemove )->pxPrevious->pxNext = ( pxItemToRemove )->pxNext;     \
        /* 确保索引指针指向正确的节点 */              \
        if( pxList->pxIndex == ( pxItemToRemove ) )                              \
        {                                                                        \
            pxList->pxIndex = ( pxItemToRemove )->pxPrevious;                    \
        }                                                                        \
                                                                                 \
        ( pxItemToRemove )->pxContainer = NULL;                                  \
        ( pxList->uxNumberOfItems )--;                                           \
    }

listINSERT_END

/*
 * 内联版本vListInsertEnd()对xTaskIncrementTick()进行了轻微优化.
 *
 * 通过多次调用listGET_OWNER_OF_NEXT_ENTRY.确保插入的节点位于最后一个节点
 *
 * 列表成员pxIndex用于遍历列表,调用listGET_OWNER_OF_NEXT_ENTRY会将pxIndex递增到列表中的下一个节点。
 * 使用vListInsertEnd将节点有效地放置在pxIndex指向的列表位置。
 * 这意味着在pxIndex参数再次指向要插入的项之前,列表中的所有其他项都将由listGET_OWNER_OF_NEXT_ENTRY返回。
 */
#define listINSERT_END( pxList, pxNewListItem )           \
    {                                                     \
        ListItem_t * const pxIndex = ( pxList )->pxIndex; \
                                                          \
        /* 链表完整性检查 */                                 \
        listTEST_LIST_INTEGRITY( ( pxList ) );                                  \
        listTEST_LIST_ITEM_INTEGRITY( ( pxNewListItem ) );                      \
                                                                                \
        /* 通过调用listGET_OWNER_OF_NEXT_ENTRY(). 确保插入的节点位于最后一个节点*/     \
        ( pxNewListItem )->pxNext = pxIndex;                 \
        ( pxNewListItem )->pxPrevious = pxIndex->pxPrevious; \
                                                             \
        pxIndex->pxPrevious->pxNext = ( pxNewListItem );     \
        pxIndex->pxPrevious = ( pxNewListItem );             \
                                                             \
        /* 将节点的pxContainer指针指向链表 */                    \
        ( pxNewListItem )->pxContainer = ( pxList );         \
                                                             \
        ( ( pxList )->uxNumberOfItems )++;                   \
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2141276.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【UE5 C++课程系列笔记】01——Visual Studio环境安装

1. 进入Visual Studio 官网&#xff0c;点击下载 下载社区版即可 下载后点击应用程序开始安装 2. 在“工作负荷”中&#xff0c;勾选如下选项 在“单个组件”中&#xff0c;勾选如下选项&#xff1a; 3. 等待下载安装 4. 安装好后&#xff0c;点击“继续但无需代码” 选择“工具…

《python语言程序设计》2018版第8章17题point类设计一个名为point的类

TypeError: point_class.dis_m() missing 1 required positional argument: ‘y2’ 这段代码为什么出错 一个又一个错误 终于摸到点头绪 #distance方法 我做的叫get_dis_m def get_dis_m(self):a_m self.__x1 - self.__x2b_m self.__y1 - self.__y2return (pow(a_m, 2) po…

k8s中的存储

目录 一 configmap 1.1 configmap的功能 1.2 configmap的使用场景 1.3 configmap创建方式 1.3.1 字面值创建 1.3.2 通过文件创建 1.3.3 通过目录创建 1.3.4 通过yaml文件创建 1.3.5 configmap的使用方式 1.3.5.1 使用configmap填充环境变量 1.3.5.2 通过数据卷使用c…

《程序猿之设计模式实战 · 观察者模式》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

AJAX 进阶 day4

目录 1.同步代码和异步代码 2.回调函数地狱和 Promise 链式调用 2.1 回调函数地狱 2.2 Promise - 链式调用 2.3 Promise 链式应用 3.async 和 await 使用 3.1 async函数和await 3.2 async函数和await_捕获错误 4.事件循环-EventLoop 4.1 事件循环 4.2 宏任务与微任务…

R语言统计分析——散点图1(常规图)

参考资料&#xff1a;R语言实战【第2版】 R语言中创建散点图的基础函数是plot(x,y)&#xff0c;其中&#xff0c;x和y是数值型向量&#xff0c;代表着图形中的&#xff08;x,y&#xff09;坐标点。 attach(mtcars) plot(wt,mpg,main"Basic Scatter plot of MPG vs. Weigh…

数据结构(Day14)

一、学习内容 结构体 概念 引入&#xff1a;定义整数赋值为10 int a10; 定义小数赋值为3.14 float b3.14; 定义5个整数并赋值 int arr[5] {1 , 2 , 3 , 4 ,5}; 定义一个学生并赋值学号姓名成绩 定义一个雪糕并赋值名称产地单价 问题&#xff1a;没有学生、雪糕 数据类型 解决&…

Text2vec -文本转向量

文章目录 一、关于 Text2vec1、Text2vec 是什么2、Features3、Demo4、News5、Evaluation英文匹配数据集的评测结果&#xff1a;中文匹配数据集的评测结果&#xff1a; 6、Release Models 二、Install三、使用1、文本向量表征1.2 Usage (HuggingFace Transformers)1.3 Usage (se…

★ C++进阶篇 ★ 多态

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第一章----多态 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSDN博客 …

2024/9/16 英语每日一段

Stark argues that, in their gummies, at least,“The total sugar in a serving is less than in half a cherry.”Of course, cherries also provide fibre, vitamin C, and antioxidants--and 14 of them would count as one of your five-a-day. Artificial sweeteners to…

Ubuntu24.04部署docker

1、更新软件 apt update 2、安装curl apt install apt-transport-https curl 3、导入阿里云GPG秘钥 curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 4、添加Docker阿里云仓库到Ubuntu 24.04的…

使用 release key 对 LineageOS 进行编译和签名

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 为什么需要使用 release key test-key 是一个公开的、众所周知的开发测试密钥&#xff0c;广泛用于测试阶段。这意味着任何人都可以获取这个密钥&#xff0c;…

详解HTTP/HTTPS协议

HTTP HTTP协议全名为超文本传输协议。HTTP协议是应用层协议&#xff0c;其传输层协议采用TCP协议。 请求—响应模型 HTTP协议采用请求-响应模型&#xff0c;通常由客户端发起请求由服务端完成响应。资源存储在服务端&#xff0c;客户端通过请求服务端获取资源。 认识URL 当…

jacoco生成单元测试覆盖率报告

前言 单元测试是日常编写代码中常用的&#xff0c;用于测试业务逻辑的一种方式&#xff0c;单元测试的覆盖率可以用来衡量我们的业务代码经过测试覆盖的比例。 目前市场上开源的单元测试覆盖率的java插件&#xff0c;主要有Emma&#xff0c;Cobertura&#xff0c;Jacoco。具体…

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0916)

接口文档: https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93850835 接口根路径&#xff1a; http://big-event-vue-api-t.itheima.net 本项目的技术栈 本项目技术栈基于 ES6、vue3、pinia、vue-router 、vite 、axios 和 element-plus http:/…

企业社会信任数据,信任指数(2004-2022年)

企业社会信任是指公众对企业及其行为的信任程度&#xff0c;这种信任度是基于企业的商业行为、产品质量、服务态度、信息披露透明度和社会责任履行等多方面因素的综合评估。 2004年&#xff0d;2022年 企业社会信任数据&#xff08;大数据&#xff09;https://download.csdn.n…

【网络】高级IO——select版本TCP服务器

目录 前言 一&#xff0c;select函数 1.1.参数一&#xff1a;nfds 1.2.参数二&#xff1a; readfds, writefds, exceptfds 1.2.1.fd_set类型和相关操作宏 1.2.2.readfds, writefds, exceptfds 1.2.3.怎么理解 readfds, writefds, exceptfds是输入输出型参数 1.3.参数三…

LeetCode[中等] 3. 无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 思路&#xff1a;滑动窗口&#xff0c;设置左右指针left与right&#xff0c;maxLength存储长度 利用HashSet性质&#xff0c;存储滑动窗口中的字符 如果没有重复的&#xff0c;那么right继续向…

5.基础漏洞——文件上传漏洞

目录 一.文件上传漏洞原理 二.文件上传漏洞条件&#xff1a; 三.上传限制手段分为两大类 (1)客户端校验 (2)服务端校验 四.具体实现 1.文件上传漏洞——绕过JS检测 2.文件上传漏洞——绕过MIME类型检测 3.文件上传漏洞——绕过黑名单检测 绕过方式:(1) 绕过方式:(2) …

yum本地源配置

yum本地源配置 1.打开虚拟机&#xff0c;点击设置。 2.选择CD/DVD&#xff0c;选择系统镜像文件&#xff0c;设备状态选择“连接”。 3.使用命令lsblk&#xff0c;查看磁盘空间&#xff0c;发现镜像文件。 4.在/dev下找到sr0镜像文件: ls /dev 5.挂载镜像文件&#xf…