FreeRTOS—列表和列表項

文章目錄

  • 一、列表與列表項
    • 1.1.列表與列表項的簡介
    • 1.2.列表與列表項相關結構體
      • 1.2.1.列表結構體
      • 1.2.2.列表項結構體
      • 1.2.3.迷你列表項
  • 二、列表相關API函數
    • 2.1.列表相關API函數介紹
      • 2.1.1.`vListInitalise( )`初始化列表函數
      • 2.1.2.`vListInitaliseItem( )`初始化列表項函數
      • 2.1.3.`vListInsertEnd( )`列表末尾插入列表項函數
      • 2.1.4.`vListInsert( )`列表插入列表項函數
      • 2.1.5.`vListRemove( )`列表移除列表項函數
  • 三、列表項的插入和刪除實驗
    • 3.1.實驗設計
    • 3.2.軟件設計
      • 3.2.1.列表插入列表項
      • 3.2.2.列表移除列表項
      • 3.2.3.列表末尾插入列表項

一、列表與列表項

1.1.列表與列表項的簡介

列表是 FreeRTOS 中的一個數據結構,概念上和鏈表有點類似,列表被用來追蹤 FreeRTOS 中的任務,列表項就是存放在列表中的項目;列表相當于鏈表,列表項相當于節點,FreeRTOS 中的列表是一個雙向環形鏈表,列表和列表項的關系和下圖所示:

在這里插入圖片描述

下面這幾點說明了使用鏈表的好處:

  • 列表的特點:列表項間的地址非連續,是人為的連接到一起的,列表項的數目是由后期添加的個數決定的,隨時可以改變。
  • 數組的特點:數組成員地址是連續的,數組在最初確定了成員數量后期無法改變。
  • 在 OS 中任務的數量是不確定的,并且任務狀態是會發生改變的,所以非常適用列表這種數據結構

1.2.列表與列表項相關結構體

1.2.1.列表結構體

有關列表的均在文件 list.c 和 list.h 中,下面代碼是 list.h 文件有關列表相關的結構體:

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;
  • 在該結構體中,包含了兩個宏,這兩個宏是確定的已知常量,FreeRTOS 通過檢查這兩個常量的值,來判斷列表的數據在程序運行過程中,是否遭到破壞,該功能一般用于調試,默認是不開啟的
  • 成員uxNumberOfItems,用于記錄列表中列表項的個數(不包含 xListEnd)
  • 成員pxIndex用于指向列表中的某個列表項,一般用于遍歷列表中的所有列表項
  • 成員變量xListEnd是一個迷你列表項,排在最末尾

下圖是列表結構示意圖:

在這里插入圖片描述

1.2.2.列表項結構體

有關列表項的均在文件 list.c 和 list.h 中,下面代碼是 list.h 文件有關列表項相關的結構體:

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 				 /* 用于檢測列表項的數據完整性 */
};
typedef struct xLIST_ITEM ListItem_t;						 /* 重定義成 ListItem_t */
  • 成員變量xItemValue為列表項的值,這個值用于按升序對列表中的列表項進行排序,例如:有任務一,數值是10;任務二,數值是20;任務三,數值是30,添加一個任務四,數值是25,任務四應該加入在任務二和任務三之間
  • 成員變量pxNextpxPrevious分別用于指向列表中列表項的下一個列表項和上一個列表項
  • 成員變量pvOwner用于指向包含列表項的對象(通常是任務控制塊)
  • 成員變量pxContainer用于指向列表項所在列表,例如:運行態、就緒態、堵塞態、掛起態

下圖是列表項結構示意圖:

在這里插入圖片描述

1.2.3.迷你列表項

迷你列表項也是列表項,但迷你列表項僅用于標記列表的末尾和掛載其他插入列表中的列表項,用戶是用不到迷你列表項的,在 list.h 文件中,有迷你列表項的相關定義,具體的代碼所示:

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;			/* 重定義成 MiniListItem_t */
  • 成員變量xItemValue為列表項的值,這個值多用于按升序對列表中的列表項進行排序。
  • 成員變量pxNextpxPrevious分別用于指向列表中列表項的下一個列表項和上一個列
    表項。
  • 迷你列表項相比于列表項,因為只用于標記列表的末尾掛載其他插入列表中的列表項
    因此不需要成員變量pxOwnerpxContainer,以節省內存開銷。

掛載其他插入列表中的列表項:初始化列表的時候總需要一個列表項提供指向上一個和下一個的指針,用于掛載新來的列表項,迷你列表項結構示意圖如下圖所示:

在這里插入圖片描述

二、列表相關API函數

2.1.列表相關API函數介紹

函數描述
vListInitalise( )初始化列表
vListInitaliseItem( )初始化列表項
vListInsertEnd( )列表末尾插入列表項(無序排列)
vListInsert( )列表插入列表項(升序排列)
vListRemove( )列表移除列表項

2.1.1.vListInitalise( )初始化列表函數

下面代碼實現的功能是將列表結構體里面的成員賦值,將遍歷列表的指針指向最后一個列表項;將列表項的值初始化至最大值為0xFFFFFFFF;將指向上一個和下一個的指針指向最后一個列表項;將列表中的列表項數量賦值為 0:

void vListInitialise(List_t * const pxList)		//參數內容:待初始化列表
{/* 初始化時,列表中只有 xListEnd,因此 pxIndex 指向 xListEnd */pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );/* xListEnd 的值初始化為最大值,用于列表項升序排序時,排在最后 */pxList->xListEnd.xItemValue = portMAX_DELAY;/* 初始化時,列表中只有 xListEnd,因此上一個和下一個列表項都為 xListEnd 本身 */pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*初始化時,列表中的列表項數量為 0(不包含 xListEnd) */pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
}

下圖是初始化后列表的結構圖:

在這里插入圖片描述

2.1.2.vListInitaliseItem( )初始化列表項函數

該函數只是把列表項所在列表指針指向空,其他成員都沒有改動:

void vListInitialiseItem(ListItem_t * const pxItem)		//參數內容:待初始化列表項
{/* 初始化時,列表項所在列表設為空 */pxItem->pxContainer = NULL;}

下圖是初始化后的列表項結構圖:

在這里插入圖片描述

2.1.3.vListInsertEnd( )列表末尾插入列表項函數

該函數用于新的列表項插入 pxIndex 指針指向的列表項的前面,是一種無序的插入方法,它的參數有兩個,第一個是需要插入的列表;第二個是新的列表項:

void vListInsertEnd(List_t * const pxList, ListItem_t * const pxNewListItem)
{/* 獲取列表 pxIndex 指向的列表項 */ListItem_t * const pxIndex = pxList->pxIndex;/* 更新待插入列表項的指針成員變量 */pxNewListItem->pxNext = pxIndex;pxNewListItem->pxPrevious = pxIndex->pxPrevious;/* 更新列表中原本列表項的指針成員變量 */pxIndex->pxPrevious->pxNext = pxNewListItem;pxIndex->pxPrevious = pxNewListItem;/* 更新待插入列表項的所在列表成員變量 */pxNewListItem->pxContainer = pxList;/* 更新列表中列表項的數量 */( pxList->uxNumberOfItems )++;
}

下圖插入列表項后的列表結構圖:

在這里插入圖片描述

2.1.4.vListInsert( )列表插入列表項函數

該函數用于新的列表項按升序排列插入列表,它有兩個參數,第一個參數是需要插入的列表;第二個是待插入的新列表項:

void vListInsert(List_t * const pxList, ListItem_t * const pxNewListItem)
{//先定義一個指針用于尋找待插入的新列表項的上一個列表項,再定義一個變量用于獲取新列表項的值用于比較ListItem_t * pxIterator;const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;/* 如果待插入列表項的值為最大值 */if( xValueOfInsertion == portMAX_DELAY ){/* 插入的位置為列表 xListEnd 前面 */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 )++;
}

下圖是插入列表項后的列表結構圖:

在這里插入圖片描述

2.1.5.vListRemove( )列表移除列表項函數

該函數用于將列表項所在列表中移除,它的參數是待移除的列表項,返回值是一個整數,表示所在列表剩余的列表項的數量:

UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove)
{List_t * const pxList = pxItemToRemove->pxContainer;/* 從列表中移除列表項 */pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;/* 如果 pxIndex 正指向待移除的列表項 */if( pxList->pxIndex == pxItemToRemove ){/* pxIndex 指向上一個列表項 */pxList->pxIndex = pxItemToRemove->pxPrevious;}else{mtCOVERAGE_TEST_MARKER();}/* 將待移除列表項的所在列表指針清空 */pxItemToRemove->pxContainer = NULL;/* 更新列表中列表項的數量 */( pxList->uxNumberOfItems )--;/* 返回列表項移除后列表中列表項的數量 */return pxList->uxNumberOfItems;
}

下圖是移除列表項后的列表結構圖:

在這里插入圖片描述

三、列表項的插入和刪除實驗

3.1.實驗設計

設計三個任務如下所示:

  • start_task:用來創建下面兩個任務
  • task1:實現 LED0 每 500ms 閃爍一次,用來提示系統正在運行
  • task2:調用列表和列表項相關的 API 函數,并且通過串口輸出相應信息

3.2.軟件設計

在 FreeRTOS 入口函數前面,定義測試列表和三個列表項:

List_t                  TestList;  
ListItem_t              ListItem1; 
ListItem_t              ListItem2; 
ListItem_t              ListItem3; 

并在 task2 函數里初始化列表和三個列表項,給這個三列表項進行賦值:

vListInitialise(&TestList);     
vListInitialiseItem(&ListItem1);
vListInitialiseItem(&ListItem2);
vListInitialiseItem(&ListItem3);ListItem1.xItemValue = 40;
ListItem2.xItemValue = 60;
ListItem3.xItemValue = 50;

把列表項的地址打印出來,證明列表項之間的準確性。

3.2.1.列表插入列表項

在 task2 函數里面編寫所有插入和刪除函數,通過下面代碼打印,可以知道最后的列表項地址為0cc,列表項 1、2、3 的地址分別是:

  • ListItem1:0d8
  • ListItem2:0ec
  • ListItem3:100
printf("項目\t\t\地址\r\n");
printf("TestList\t\t0x%p\t\r\n", &TestList);
printf("TestList->pxIndex\t0x%p\t\r\n", TestList.pxIndex);
printf("TestList->xListEnd\t0x%p\t\r\n", (&TestList.xListEnd));
printf("ListItem1\t\t0x%p\t\r\n", &ListItem1);
printf("ListItem2\t\t0x%p\t\r\n", &ListItem2);
printf("ListItem3\t\t0x%p\t\r\n", &ListItem3);
printf("/**************************結束***************************/\r\n");
printf("按下KEY0鍵繼續!\r\n\r\n\r\n");
while (key_scan(0) != KEY0_PRES)
{vTaskDelay(10);
}

在這里插入圖片描述

在前面的初始化,task3 的值為 50,應該插入在 task1 和 task2 之間,下面將列表項 1、2、3 簡稱為 1、2、3;理論上來說,按升序排列,1 是最小的數值,2 是最大的數值,3 排中間,因此 1 的 Next 應該指向 3 的地址,1 的 Previous 應該指向 End (0cc);2 的 Next 應該指向 End (0cc),2 的 Previous 應該指向 3 的地址;而 3 的 Next 應該指向 2 的地址,3 的 Previous 應該指向 1 的地址;最后通過串口輸出的數據證明,情況確實如此:

//在列表分別插入列表項1、2、3
vListInsert((List_t*    )&TestList,        (ListItem_t*)&ListItem1); 
vListInsert((List_t*    )&TestList,       (ListItem_t*)&ListItem2);       
vListInsert((List_t*    )&TestList,        (ListItem_t*)&ListItem3);      
printf("項目\t\t\地址\r\n");
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/**************************結束***************************/\r\n");
printf("按下KEY0鍵繼續!\r\n\r\n\r\n");
while (key_scan(0) != KEY0_PRES)
{vTaskDelay(10);
}

在這里插入圖片描述

3.2.2.列表移除列表項

本次目標是移除列表項 2,只需要證明 1 的 Next 指向 3,1 的 Previous 指向 End(0cc);3 的 Next 指向 End(0cc) ,3 的 Previous 指向 1:

uxListRemove((ListItem_t*   )&ListItem2); 	//需要移除的列表項
printf("項目\t\t\地址\r\n");
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/**************************結束***************************/\r\n");
printf("按下KEY0鍵繼續!\r\n\r\n\r\n");
while (key_scan(0) != KEY0_PRES)
{vTaskDelay(10);
}

在這里插入圖片描述

3.2.3.列表末尾插入列表項

該函數的設定是將新的列表項,插入到 pxIndex 所指的列表項的前面,由第一個步驟可以發現,指針 pxIndex 指向 End ,因此現在新的列表項將會在 End 前面插入,輸出的結果和升序排列插入一樣:

vListInsertEnd((List_t*     )&TestList,     //列表(ListItem_t* )&ListItem2);   //需要插入的列表項
printf("項目\t\t\地址\r\n");
printf("TestList->pxIndex\t\t0x%p\r\n", TestList.pxIndex);
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/**************************結束***************************/\r\n");

在這里插入圖片描述

想要將 2 插入在指定列表項之前,只需修改指針 pxIndex 所指的列表項即可,例如:在列表項 1 前面插入:

TestList.pxIndex = &ListItem1; //pxIndex指向列表項1
vListInsertEnd((List_t*     )&TestList,     //列表(ListItem_t* )&ListItem2);   //需要插入的列表項
printf("項目\t\t\地址\r\n");
printf("TestList->pxIndex\t\t0x%p\r\n", TestList.pxIndex);
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/**************************結束***************************/\r\n");

2 的 Next 指向 1 ;2 的 Previous 指向 End:

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89389.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89389.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89389.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

超詳細 anji-captcha滑塊驗證uniapp微信小程序前端組件

由于步驟太多&#xff0c;字數太多&#xff0c;廢話也太多&#xff0c;所以前后端分開講了&#xff0c;后端文章請看&#xff1a; 超詳細 anji-captcha滑塊驗證springbootuniapp微信小程序前后端組合https://blog.csdn.net/new_public/article/details/149116742 anji-captcha…

面向對象編程篇

文章目錄一、思維導圖二、詳細內容第 6 章&#xff1a;面向對象編程基礎6.1 面向對象編程的概念和優勢6.2 類和對象的定義與創建6.3 類的屬性和方法6.4 構造函數&#xff08;__init__&#xff09;和析構函數&#xff08;__del__&#xff09;6.5 封裝、繼承和多態的實現第 7 章&…

虛擬商品自動化實踐:閑魚訂單防漏發與模板化管理的技術解析

最近阿燦發現了一款閑魚虛擬商品賣家必備神器&#xff01;告別手動發貨&#xff0c;訂單自動處理&#xff0c;防錯防漏&#xff0c;支持課程、激活碼、電子書等多種商品&#xff0c;預設模板更省心。文末獲取工具&#xff01;最厲害的是&#xff0c;你完全不用一直開著電腦。以…

【Zephyr開發實踐系列】08_NVS文件系統調試記錄

文章目錄前言一、NVS原理介紹&#xff1a;二、BUG-NO1&#xff1a;將NVS運用在NAND-Flash類大容量存儲設備2.1 情況描述&#xff1a;2.2 BUG復現&#xff1a;文件系統設備樹構建測試應用編寫&#xff08;導致錯誤部分&#xff09;&#xff1a;問題呈現&#xff1a;2.3 問題簡述…

網絡安全第二次作業

靶場闖關1~8 1. 在url后的name后輸入payload ?name<script>alert(1)</script> 2. 嘗試在框中輸入上一關的payload,發現并沒有通過&#xff0c;此時我們可以點開頁面的源代碼看看我們輸入的值被送到什么地方去了 從圖中可以看到&#xff0c;我們輸入的值被送到i…

LangChain 源碼剖析(七)RunnableBindingBase 深度剖析:給 Runnable“穿衣服“ 的裝飾器架構

每一篇文章都短小精悍&#xff0c;不啰嗦。一、功能定位&#xff1a;Runnable 的 "增強包裝器"RunnableBindingBase 是 LangChain 中實現裝飾器模式的核心組件。它就像給原有 Runnable 套上一件 "功能外套"—— 不改變原有 Runnable 的核心邏輯&#xff0c…

為 Git branch 命令添加描述功能

寫在最前面的使用方式 查看 所有分支的備注 git branch.notes創建分支并為分支添加備注 git co -b feat/oauth -m 第三方用戶登錄對分支描述的添加與清除 添加 git branch.note --add 清除 git branch.note --clear &#x1f4dd; 為 Git branch 命令添加描述功能 &#x…

LeetCode|Day18|20. 有效的括號|Python刷題筆記

LeetCode&#xff5c;Day18&#xff5c;20. 有效的括號&#xff5c;Python刷題筆記 &#x1f5d3;? 本文屬于【LeetCode 簡單題百日計劃】系列 &#x1f449; 點擊查看系列總目錄 >> &#x1f4cc; 題目簡介 題號&#xff1a;20. 有效的括號 難度&#xff1a;簡單 題目…

使?Pytorch構建?個神經?絡

關于torch.nn:使?Pytorch來構建神經?絡, 主要的?具都在torch.nn包中.nn依賴于autograd來定義模型, 并對其?動求導.構建神經?絡的典型流程:定義?個擁有可學習參數的神經?絡遍歷訓練數據集處理輸?數據使其流經神經?絡計算損失值將?絡參數的梯度進?反向傳播以?定的規則…

網絡爬蟲的詳細知識點

基本介紹 什么是網絡爬蟲 網絡爬蟲&#xff08;Web Crawler&#xff09;是一種自動化程序&#xff0c;用于從互聯網上抓取、解析和存儲網頁數據。其核心功能是模擬人類瀏覽行為&#xff0c;通過HTTP/HTTPS協議訪問目標網站&#xff0c;提取文本、鏈接、圖片或其他結構化信息&…

AndroidX中ComponentActivity與原生 Activity 的區別

一、AndroidX 與原生 Activity 的區別 1. 概念與背景 原生 Activity&#xff1a;指 Android 早期&#xff08;API 1 起&#xff09;就存在于 android.app 包下的 Activity 類&#xff08;如 android.app.Activity&#xff09;&#xff0c;是 Android 最初的 Activity 實現&…

Spring AI 使用 Elasticsearch 作為向量數據庫

前言 嗨&#xff0c;大家好&#xff0c;我是雪荷&#xff0c;最近在公司開發 AI 知識庫&#xff0c;同時學到了一些 AI 開發相關的技術&#xff0c;這期先與大家分享一下如何用 ES 當做向量數據庫。 安裝ES 第一步我們先安裝 Elasticsearch&#xff0c;這里建議 Elasticsear…

TypeScript 配置全解析:tsconfig.json、tsconfig.app.json 與 tsconfig.node.json 的深度指南

前言在現代前端和后端開發中&#xff0c;TypeScript 已經成為許多開發者的首選語言。然而&#xff0c;TypeScript 的配置文件&#xff08;特別是多個配置文件協同工作時&#xff09;常常讓開發者感到困惑。本文將深入探討 tsconfig.json、tsconfig.app.json 和 tsconfig.node.j…

讀書筆記(學會說話)

1、一個人只有會說話&#xff0c;才會有好人緣&#xff0c;做事才會順利。會說話的人容易成功。善于說話的人易成功&#xff0c;而不善說話的人往往寸步難行。我們要把話說得好聽&#xff0c;同時更要把事做得漂亮。或許一句話&#xff0c;一件事&#xff0c;就可能使人生的旅途…

私有服務器AI智能體搭建-大模型選擇優缺點、擴展性、可開發

以下是主流 AI 框架與模型的對比分析&#xff0c;涵蓋其優缺點、擴展性、可開發性等方面。 文章目錄一、AI 框架對比二、主流大模型對比三、擴展性對比總結四、可開發性對比總結五、選擇建議&#xff08;按場景&#xff09;六、未來趨勢一、AI 框架對比 框架優點缺點擴展性可開…

OpenCV直線段檢測算法類cv::line_descriptor::LSDDetector

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 該類用于實現 LSD (Line Segment Detector) 直線段檢測算法。LSD 是一種快速、準確的直線檢測方法&#xff0c;能夠在不依賴邊緣檢測的前提下直接從…

Go語言流程控制(if / for)

分支結構package mainimport ("fmt""strconv" )/* 1.順序結構 2.分支結構 3.循環結構 *//* if 條件1 {// 條件1為真時執行的代碼 } else if 條件2 {// 條件1為假但條件2為真時執行的代碼 } else {// 所有條件均為假時執行的代碼 }一種特殊的條件分支結構if…

wx小程序設置沉浸式導航文字高度問題

第一步&#xff1a;在app.json中設置"navigationStyle": "custom"第二步驟&#xff1a;文件的home.js中// pages/test/test.js Page({/*** 頁面的初始數據*/data: {statusBarHeight: 0,navBarHeight: 44 // 自定義導航內容區高度(單位px)},/*** 生命周期函…

C++算法競賽篇:DevC++ 如何進行debug調試

C算法競賽篇&#xff1a;DevC 如何進行debug調試前言一、準備工作&#xff1a;編譯生成可執行程序二、核心步驟&#xff1a;設置斷點與啟動調試1. 設置斷點2. 啟動調試模式三、調試操作&#xff1a;逐步執行與變量監控1. 逐步執行代碼2. 監控變量值變化四、調試結束前言 在算法…

語音大模型速覽(三)- cosyvoice2

CosyVoice 2: Scalable Streaming Speech Synthesis with Large Language Models 論文鏈接&#xff1a;https://arxiv.org/pdf/2412.10117代碼鏈接&#xff1a;https://github.com/FunAudioLLM/CosyVoice 一句話總結 CosyVoice 2 是一款改進的流式語音合成模型&#xff0c;其…