00. 目录

文章目录

  • 00. 目录
  • 01. 概述
  • 02. 列表
  • 03. 列表项
  • 04. 列表相关宏
  • 05. 列表相关函数
    • 5.1 初始化列表
    • 5.2 初始化列表项
    • 5.3 列表项插入函数
    • 5.4 列表项末尾插入
    • 5.5 列表项删除
    • 5.6 列表遍历
  • 06. 附录
  • 07. 参考

01. 概述

要想看懂FreeRTOS 源码并学习其原理,有一个东西绝对跑不了,那就是FreeRTOS 的列表和列表项。列表和列表项是FreeRTOS 的一个数据结构,FreeRTOS 大量使用到了列表和列表项,它是FreeRTOS 的基石。要想深入学习并理解FreeRTOS,那么列表和列表项就必须首先掌握,否则后面根本就没法进行。

列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。用户程序如果有需要,也可以使用列表。

FreeRTOS列表使用指针指向列表项。一个列表(list)下面可能有很多个列表项(list item),每个列表项都有一个指针指向列表。如下图所示。

02. 列表

列表是FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪FreeRTOS中的任务。与列表相关的全部东西都在文件list.c 和list.h 中。在list.h 中定义了一个叫List_t 的结构体,如下:

typedef struct xLIST
{listFIRST_LIST_INTEGRITY_CHECK_VALUE                        /*用于检测列表项数据是否完整*/configLIST_VOLATILE UBaseType_t uxNumberOfItems;ListItem_t * configLIST_VOLATILE pxIndex;                   /*用于遍历列表*/MiniListItem_t xListEnd;                                    /*列表项*/listSECOND_LIST_INTEGRITY_CHECK_VALUE                       /*用于检测列表项数据是否完整*/
}List_t;

(1) 和(5) 、这两个都是用来检查列表完整性的, 需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为1,开启以后会向这两个地方分别添加一个变量xListIntegrityValue1 和xListIntegrityValue2,在初始化列表的时候会这两个变量中写入一个特殊的值,默认不开启这个功能。
(2)、uxNumberOfItems 用来记录列表中列表项的数量。
(3)、pxIndex 用来记录当前列表项索引号,用于遍历列表。
(4)、列表中最后一个列表项,用来表示列表结束,此变量类型为MiniListItem_t,这是一个迷你列表项。

03. 列表项

列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项。这两个都在文件list.h 中有定义。

xLIST_ITEM列表项

struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/configLIST_VOLATILETickType_t xItemValue;           /*列表项值*/struct xLIST_ITEM * configLIST_VOLATILE pxNext;      /*指向列表中下一个列表项*/struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  /*指向列表中上一个列表项*/void * pvOwner;                                     /*指向一个任务TCB*/void * configLIST_VOLATILE pvContainer;             /*指向包含该列表项的列表 */listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*用于检测列表项数据是否完整*/
};
typedef struct xLIST_ITEM ListItem_t;

(1)和(7)、用法和列表一样,用来检查列表项完整性的。以后我们在学习列表项的时候不讨论这个功能!
(2)、xItemValue 为列表项值。
(3)、pxNext 指向下一个列表项。
(4)、pxPrevious 指向前一个列表项,和pxNext 配合起来实现类似双向链表的功能。
(5)、pvOwner 记录此链表项归谁拥有,通常是任务控制块。
(6)、pvContainer 用来记录此列表项归哪个列表。注意和pvOwner 的区别,在前面讲解任务控制块TCB_t 的时候说了在TCB_t 中有两个变量xStateListItem 和xEventListItem,这两个变量的类型就是ListItem_t,也就是说这两个成员变量都是列表项。以xStateListItem 为例,当创建一个任务以后xStateListItem 的pvOwner 变量就指向这个任务的任务控制块,表示xSateListItem属于此任务。当任务就绪态以后xStateListItem 的变量pvContainer 就指向就绪列表,表明此列表项在就绪列表中。举个通俗一点的例子:小王在上二年级,他的父亲是老王。如果把小王比作列表项,那么小王的pvOwner 属性值就是老王,小王的pvContainer 属性值就是二年级。

xMINI_LIST_ITEM列表项

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;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

(1)、用于检查迷你列表项的完整性。

(2)、xItemValue 记录列表列表项值。
(3)、pxNext 指向下一个列表项。
(4)、pxPrevious 指向上一个列表项。
可以看出迷你列表项只是比列表项少了几个成员变量,迷你列表项有的成员变量列表项都有的,没感觉有什么本质区别啊?那为什么要弄个迷你列表项出来呢?那是因为有些情况下我们不需要列表项这么全的功能,可能只需要其中的某几个成员变量,如果此时用列表项的话会造成内存浪费!比如上面列表结构体List_t 中表示最后一个列表项的成员变量xListEnd 就是MiniListItem_t 类型的。

04. 列表相关宏

/** Access macro to set the owner of a list item.  The owner of a list item* is the object (usually a TCB) that contains the list item.** \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER* \ingroup LinkedList*/
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )    ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )/** Access macro to get the owner of a list item.  The owner of a list item* is the object (usually a TCB) that contains the list item.** \page listGET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER* \ingroup LinkedList*/
#define listGET_LIST_ITEM_OWNER( pxListItem )             ( ( pxListItem )->pvOwner )/** Access macro to set the value of the list item.  In most cases the value is* used to sort the list in descending order.** \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE* \ingroup LinkedList*/
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )     ( ( pxListItem )->xItemValue = ( xValue ) )/** Access macro to retrieve the value of the list item.  The value can* represent anything - for example the priority of a task, or the time at* which a task should be unblocked.** \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE* \ingroup LinkedList*/
#define listGET_LIST_ITEM_VALUE( pxListItem )             ( ( pxListItem )->xItemValue )/** Access macro to retrieve the value of the list item at the head of a given* list.** \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE* \ingroup LinkedList*/
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )        ( ( ( pxList )->xListEnd ).pxNext->xItemValue )/** Return the list item at the head of the list.** \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY* \ingroup LinkedList*/
#define listGET_HEAD_ENTRY( pxList )                      ( ( ( pxList )->xListEnd ).pxNext )/** Return the next list item.** \page listGET_NEXT listGET_NEXT* \ingroup LinkedList*/
#define listGET_NEXT( pxListItem )                        ( ( pxListItem )->pxNext )/** Return the list item that marks the end of the list** \page listGET_END_MARKER listGET_END_MARKER* \ingroup LinkedList*/
#define listGET_END_MARKER( pxList )                      ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )/** Access macro to determine if a list contains any items.  The macro will* only have the value true if the list is empty.** \page listLIST_IS_EMPTY listLIST_IS_EMPTY* \ingroup LinkedList*/
#define listLIST_IS_EMPTY( pxList )                       ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )/** Access macro to return the number of items in the list.*/
#define listCURRENT_LIST_LENGTH( pxList )                 ( ( pxList )->uxNumberOfItems )/** Access function to obtain the owner of the next entry in a list.** The list member pxIndex is used to walk through a list.  Calling* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list* and returns that entry's pxOwner parameter.  Using multiple calls to this* function it is therefore possible to move through every item contained in* a list.** The pxOwner parameter of a list item is a pointer to the object that owns* the list item.  In the scheduler this is normally a task control block.* The pxOwner parameter effectively creates a two way link between the list* item and its owner.** @param pxTCB pxTCB is set to the address of the owner of the next list item.* @param pxList The list from which the next item owner is to be returned.** \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY* \ingroup LinkedList*/
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \{                                                                                          \List_t * const pxConstList = ( pxList );                                               \/* Increment the index to the next item and return the item, ensuring */               \/* we don't return the marker used at the end of the list.  */                         \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \{                                                                                      \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \}                                                                                      \( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \}/** Access function to obtain the owner of the first entry in a list.  Lists* are normally sorted in ascending item value order.** This function returns the pxOwner member of the first item in the list.* The pxOwner parameter of a list item is a pointer to the object that owns* the list item.  In the scheduler this is normally a task control block.* The pxOwner parameter effectively creates a two way link between the list* item and its owner.** @param pxList The list from which the owner of the head item is to be* returned.** \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY* \ingroup LinkedList*/
#define listGET_OWNER_OF_HEAD_ENTRY( pxList )            ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )/** Check to see if a list item is within a list.  The list item maintains a* "container" pointer that points to the list it is in.  All this macro does* is check to see if the container and the list match.** @param pxList The list we want to know if the list item is within.* @param pxListItem The list item we want to know if is in the list.* @return pdTRUE if the list item is in the list, otherwise pdFALSE.*/
#define listIS_CONTAINED_WITHIN( pxList, pxListItem )    ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )/** Return the list a list item is contained within (referenced from).** @param pxListItem The list item being queried.* @return A pointer to the List_t object that references the pxListItem*/
#define listLIST_ITEM_CONTAINER( pxListItem )            ( ( pxListItem )->pxContainer )/** This provides a crude means of knowing if a list has been initialised, as* pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()* function.*/
#define listLIST_IS_INITIALISED( pxList )                ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

05. 列表相关函数

5.1 初始化列表

列表结构体中包含一个列表项成员,主要用于标记列表结束。初始化列表就是把这个列表项插入到列表中。

void vListInitialise( List_t * const pxList )
{/*列表索引指向列表项*/pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );                  /* 设置为最大可能值 */pxList->xListEnd.xItemValue =portMAX_DELAY;/* 列表项xListEnd的pxNext和pxPrevious指针指向了它自己 */pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );pxList->uxNumberOfItems = ( UBaseType_t) 0U;/* 设置为已知值,用于检测列表数据是否完整*/listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );
}

如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一个已知值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。

5.2 初始化列表项

列表项的初始比较简单,只要确保列表项不在任何列表中即可。

void vListInitialiseItem( ListItem_t * const pxItem )
{pxItem->pvContainer = NULL;/*设置为已知值,用于检测列表项数据是否完整*/listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
}

如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。

5.3 列表项插入函数

每个列表项对象都有一个列表项值(xItemValue),通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。调用API函数vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以将pxNewListItem指向的列表项插入到pxList指向的列表中,列表项在列表的位置由pxNewListItem->xItemValue决定,按照升序排列。

void vListInsert( List_t * const pxList,ListItem_t * const pxNewListItem )
{ListItem_t * pxIterator;const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;/* 检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*//* 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 TCBs 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. *//*将新的列表项插入到列表,根据xItemValue的值升序插入列表。*/if( xValueOfInsertion == portMAX_DELAY ){pxIterator = pxList->xListEnd.pxPrevious;}else{/* *** NOTE ************************************************************  If you find your application is crashing here then likely causes are*  listed below.  In addition see https://www.FreeRTOS.org/FAQHelp.html for*  more tips, and ensure configASSERT() is defined!*  https://www.FreeRTOS.org/a00110.html#configASSERT**   1) Stack overflow -*      see https://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*      https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html and the definition*      of configMAX_SYSCALL_INTERRUPT_PRIORITY on*      https://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?).**********************************************************************///xListEnd表示列表的末尾for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM.  This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */{/* 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->pxContainer = pxList;( pxList->uxNumberOfItems )++;
}

根据xItemValue的值将新的列表项插入到列表。如果列表中存在与新列表项xItemValue值相同的列表项,则新插入的列表项位于它之后。如果列表项的xItemValue值等于portMAX_DELAY(列表结束标记,我们在讲列表数据结构时,说到每个列表数据结构体中都有一个列表项成员xListEnd,用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF或者0xFFFFFFFF。这个常数在移植层定义,即宏portMAX_DELAY),则表示到达了列表结束位置。

5.4 列表项末尾插入

API函数vListInsertEnd()是简单的将列表项插入到列表的末端。

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{ListItem_t* const pxIndex = pxList->pxIndex;/*检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/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->pvContainer = ( void* ) pxList;( pxList->uxNumberOfItems )++;
}

5.5 列表项删除

列表项的删除只是将指定的列表项从列表中删除,并不会将这个列表项的内存给释放掉。

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;}else{mtCOVERAGE_TEST_MARKER();}pxItemToRemove->pxContainer = NULL;( pxList->uxNumberOfItems )--;return pxList->uxNumberOfItems;
}

5.6 列表遍历

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \{                                                                                          \List_t * const pxConstList = ( pxList );                                               \/* Increment the index to the next item and return the item, ensuring */               \/* we don't return the marker used at the end of the list.  */                         \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \{                                                                                      \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \}                                                                                      \( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \}

06. 附录

6.1 【STM32】STM32系列教程汇总

网址:【STM32】STM32系列教程汇总

07. 参考

《FreeRTOS Reference Manual》

《Using the FreeRTOS Real Time Kernel -A Practical Guide》

《The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors,3rd Edition》

【STM32】FreeRTOS列表和列表项详解相关推荐

  1. python列表切片后得到剩余列表_python列表切片和嵌套列表取值操作详解

    python列表切片和嵌套列表取值操作详解 给出列表切片的格式: [开头元素::步长] # 输出直到最后一个元素,(最后一个冒号和步长可以省略,下同) [开头元素:结尾元素(不含):步长] # 其中, ...

  2. layui添加复选框_对layui初始化列表的CheckBox属性详解,初始化属性

    对layui初始化列表的CheckBox属性详解,初始化属性 通常layui前端页面完全按照layui官网的例子写所有的页面初始化都没有问题,但是那只是静态页面.当加入后台去动态加载页面的时候有写样式 ...

  3. php栏目页内容排序问题,Dedecms频道列表页栏目排序问题详解

    织梦Dedecms频道列表页栏目排序问题详解,问题描述如下: 各位大大,小弟我想在首页调用6个栏目,typeid分别是1,2,3,4,5,40,默认的排序小弟不想要,希望改为1,40,3,4,5,2 ...

  4. Chapter Four : Python 序列之列表、元组操作详解合集

    目录 一.列表 1. 列表基本操作:定义列表.删除列表.访问列表.遍历列表 2. 列表常用方法及操作详解 2.1 添加元素:append().extend().insert().+ 运算符.*运算符 ...

  5. python用列表推导式_python 列表推导式使用详解

    所谓的列表推导式,就是指的轻量级循环创建列表. 基本使用方式 # 创建一个0-10的列表 a = [x for x in range(11)] print(a) """ ...

  6. 网络安全等级保护测评高风险判定指引_等保知识|测评高风险项详解:安全管理中心...

    "安全管理中心"是等级保护2.0标准新增的层面,其要求侧重在对设备运行状况.审计数据.安全策略.恶意代码.补丁升级.安全事件等集中式的分析与管控.<网络安全法>第二十一 ...

  7. grep的-A-B-选项详解

    grep的-A-B-选项详解 grep能找出带有关键字的行,但是工作中有时需要找出该行前后的行,下面是解释 1. grep -A1 keyword filename找出filename中带有keywo ...

  8. JMeter学习(五)---察看结果树和聚合报告指标项详解

    在用JMeter做测试过程中,用到最多的监听器就是察看结果树和聚合报告啦,那取样器中的各项指标代表什么含义呢?我觉得了解一下还是很有必要的,有助于我们观察和分析结果.下面开始介绍: 察看结果树 界面如 ...

  9. STM32应用IAP进行程序更新详解及实例

      这是以前就想写的一个小专题关于IAP,以及IAP在STM32编程的应用,专题分三小节,主要介绍常见的单片机烧录方式,IAP的实际应用,以及Ymodem协议在IAP编程中应用,在笔记吃灰很久了,终于 ...

  10. STM32 VBAT外围电路接法详解--备用电源(纽扣电池)

    STM32 VBAT外围电路接法详解 给大家看几块开发板的VBAT外围电路的设计图: (1)不满足 (2)符合要求,但不是最佳 (3)不满足        (4)不满足        (5)最好的设计 ...

最新文章

  1. vs + ffmpeg------待续
  2. 超越 一切还刚刚开始
  3. 关于使用REST API
  4. Errors occurred during the build. Errors running builder 'Validation' on pro
  5. php二维数组的取值与转换
  6. jquery级试题_腾讯2020前端面试题含答案解析
  7. 登录页跳转时保存用户信息-遇坑记
  8. win7开机突然变得很慢_几个步骤教你解决win7旗舰版开机超级慢
  9. 计算机鼠标显示停顿原因,经常遇到鼠标指针停顿卡的解决方法
  10. 问题:为什么我们计算的GDP增长率跟统计局公布的不一样
  11. 前段vue+后端接口PHP实现万年历(带上节假日天干地支凶吉星座神)
  12. Android 11 WiFi热点打开与关闭接口
  13. FPGA中的乒乓操作
  14. 赛扬n5095处理器怎么样 英特尔n5095核显相当于什么水平
  15. 什么是短视频电商,短视频电商的商业模式标题】
  16. Ubuntu多硬盘luks全盘加密自动解锁(硬件变更后失效)的方法
  17. astah_激活步骤
  18. 编译原理晦涩难懂-2-正则表达式
  19. 英语6级词汇量【原创】
  20. oj1904: 寄居蟹与海葵

热门文章

  1. ASP.NET2.0数据操作之创建数据访问层(3)
  2. 7-25 雨刷程序功能扩展设计 (100 分)
  3. 郑州军办计算机学校,郑州市国防科技学校2019级新生开启军训模式
  4. RHEL7.2系统下的软件管理(yum)、本地yum源和网络yum源的搭建
  5. Mysql Order By 注入总结
  6. 如何做好性能测试_流程篇
  7. 【C++ 第七章 个人银行账户管理程序案例】
  8. 【Spring 基础篇三】属性注入与属性编辑器
  9. hibernate数据的三种存在状态(只与事务有关)
  10. SharePoint 2010 隐藏快速启动栏(左侧导航)