linux驅動編程 - kfifo先進先出隊列

簡介:

????????kfifo是Linux Kernel里面的一個 FIFO(先進先出)數據結構,它采用環形循環隊列的數據結構來實現,提供一個無邊界的字節流服務,并且使用并行無鎖編程技術,即當它用于只有一個入隊線程和一個出隊線程的場情時,兩個線程可以并發操作,而不需要任何加鎖行為,就可以保證kfifo的線程安全。
????????FIFO主要用于緩沖速度不匹配的通信。

下面圖解kfifo工作過程:

藍色表示kfifo剩余空間,紅色表示kfifo已占用空間

1)空的kfifo

2)put數據到buffer后

3)從buffer中get數據后

4)當此時put到buffer中的數據長度超出in到末尾長度時,則將剩下的移到頭部去

注意,kfifo如果只有一個寫入者,一個讀取者,是不需要鎖的。但是多對一的情況,多的那方需要上鎖。如:多個寫入者,一個讀取者,需對寫入者上鎖。 反之,如果有多個讀取者,一個寫入者,需對讀取者上鎖。

一、kfifo常用函數介紹

Linux內核中的路徑:lib/kfifo.c、include/linux/kfifo.h

頭文件:#include <linux/kfifo.h>

常用函數 / 宏功能
DECLARE_KFIFO_PTR(fifo, type)定義一個名字為fifo,element類型為type,其數據需要kfifo_alloc動態分配
DECLARE_KFIFO(fifo, type, size)定義一個名字為fifo,element類型為type,element個數為size,其數據靜態存儲在結構體中,size需為常數且為2的整數次方
INIT_KFIFO(fifo)初始化DECLARE_KFIFO接口定義的fifo
DEFINE_KFIFO(fifo, type, size)定義并初始化fifo
kfifo_initialized(fifo)fifo是否初始化
kfifo_recsize(fifo)返回fifo的recsize
kfifo_size(fifo)返回fifo的size
kfifo_reset(fifo)將in和out置0,注意:需要上鎖
kfifo_reset_out(fifo)設置out=in,由于只修改out,因此在讀者上下文,且只有一個讀者時,是安全的。否則需要上鎖。
kfifo_len(fifo)返回fifo的總size
kfifo_is_empty(fifo)fifo是否為空 (in == out)
kfifo_is_full(fifo)fifo是否滿
kfifo_avail(fifo)獲取隊列的空閑空間長度
kfifo_skip(fifo)跳過一個element
kfifo_peek_len(fifo)獲取下一個element的字節長度。
kfifo_alloc(fifo, size, gfp_mask)為指針式FIFO分配空間并初始化,成功返回0,錯誤則返回負數錯誤碼
kfifo_free(fifo)釋放kfifo_alloc分配的內存
kfifo_init(fifo, buffer, size)用戶自己申請緩存,然后傳遞給fifo進行初始化,成功返回0,錯誤則返回負數錯誤碼
kfifo_put(fifo, val)這是一個宏,將val賦值給一個FIFO type類型的臨時變量,然后將臨時變量入隊。存放一個element,如果成功返回入隊的elements個數。如果FIFO滿,則返回0。
kfifo_get(fifo, val)

val是一個指針,內部將val賦值給一個ptr指針類型的臨時變量,并拷貝sizeof(*ptr)長度到val的地址。拷貝一個element。
如果FIFO為空,返回0,否則返回拷貝的element數。

kfifo_peek(fifo, val)和kfifo_get相同,除了不更新out外。
kfifo_in(fifo, but, n)入隊n個elemnts。返回工程入隊的elements數。
kfifo_in(fifo, buf, n, lock)加鎖入隊。加鎖方式為spin_lock_irqsave
kfifo_out(fifo, buf, n)出隊n個elements,返回成功拷貝的elements數
kfifo_out_spinlocked(fifo, buf, n, lock)加鎖出隊。加鎖方式位spin_lock_irqsave
kfifo_from_user(fifo, from, len, copied)

復制用戶空間的數據到kfifo

最多拷貝len個字節,參考record FIFO和非record FIFO的對應底層接口。
kfifo_to_user(fifo, to, len, copied)

復制kfifo中的數據到用戶空間

最多拷貝len個字節到用戶空間,參考record FIFO和非record FIFO的對應底層接口。
kfifo_out_peek(fifo, buf, n)peek n個elements的數據,但是內部out不動,返回拷貝的elements個數

1、結構體定義

1.1 struct __kfifo 結構體

struct __kfifo {unsigned int	in;           //入隊指針,指向下一個元素可被插入的位置unsigned int	out;          //出隊指針,指向即將出隊的第一個元素unsigned int	mask;         //向上擴展成2的冪queue_size-1unsigned int	esize;        //每個元素的大小,單位為字節void		*data;            //存儲數據的緩沖區
};

下圖可以直觀的表示各結構體成員之間的關系:

1.2 struct kfifo 結構體


#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \union { \struct __kfifo	kfifo; \datatype	*type; \const datatype	*const_type; \char		(*rectype)[recsize]; \ptrtype		*ptr; \ptrtype const	*ptr_const; \}#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \
{ \__STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \type		buf[0]; \
}struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);

kfifo結構體展開后格式如下:

struct kfifo
{union{struct __kfifo    kfifo;            //__kfifo是kfifo的成員unsigned char        *type;const unsigned char  *const_type;char                 (*rectype)[0];void                 *ptr;void const           *ptr_const;  };unsigned char buf[0];
}

kfifo怎么和其它字段是聯合的?其它字段讀寫豈不是會覆蓋kfifo的內容。其實這又是內核的一個技巧,其它字段不會讀寫數據,只是編譯器用來獲取相關信息?。

比如:

獲取recsize:

#define kfifo_recsize(fifo) ? ? (sizeof(*(fifo)->rectype))
通過kfifo_alloc分配buf存儲空間時,獲取塊的大小

__kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) :?

2、初始化kfifo

聲明kfifo有2種方式:

  • DECLARE_KFIFO_PTR?配合 kfifo_alloc 用于動態申請kfifo;
  • DECLARE_KFIFO 用于靜態定義kfifo;
功能相似方法

DECLARE_KFIFO_PTR(fifo, type)

參數:

fifo:要定義的kfifo的名字

type:元素的類型

宏定義一個kfifo指針對象,會設置type buf[]數組的大小為0,因此需配合 kfifo_alloc ?動態分配buf的存儲空間struct kfifo fifo;

DECLARE_KFIFO(fifo, type, size)

參數:

fifo:要定義的kfifo的名字

type:元素的類型

size:kfifo可容納的元素個數,必須是2的冪

靜態聲明一個kfifo對象,設置type buf[] 大小為size、類型為 type 的數組DEFINE_KFIFO

筆者常用到動態申請方式,因此主要介紹動態申請方式。

動態申請除了用?DECLARE_KFIFO_PTR,還能用 struct kfifo 創建結構體,如:

struct kfifo fifo;? ? ? ? #可替代?DECLARE_KFIFO_PTR(fifo, unsigned char)

這種方式可替代 DECLARE_KFIFO_PTR(fifo, unsigned char),它們都用到 __STRUCT_KFIFO_PTR,僅傳入的第3個參數不同。

/*?struct kfifo結構體定義 */
struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);/*?DECLARE_KFIFO_PTR宏定義?*/
#define STRUCT_KFIFO_PTR(type) \struct __STRUCT_KFIFO_PTR(type, 0, type)#define DECLARE_KFIFO_PTR(fifo, type) ? STRUCT_KFIFO_PTR(type) fifo

2.1 動態申請

方法一:

struct kfifo fifo = {0};????????????????????????????????//定義一個 struct kfifo 變量

kfifo_alloc(&fifo, 4096, GFP_KERNEL);? //使用 kfifo_alloc 動態申請內存空間,大小為4096

方法二:

DECLARE_KFIFO_PTR(fifo, unsigned char);????????//申請

INIT_KFIFO(fifo);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //初始化?

kfifo_alloc(&fifo, 4096, GFP_KERNEL);???//使用 kfifo_alloc 動態申請內存空間,大小為4096

注意:動態分配最后需要調用?kfifo_free 釋放

2.2 靜態定義

方法一:

DECLARE_KFIFO(fifo, char, 512);? ? ? ? //靜態申明,type buf[] 大小為512,類型為char

INIT_KFIFO(fifo);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//初始化fifo結構

方法二:

DEFINE_KFIFO(fifo, char, 512)? ? ? ? ? ? ?//同上

3、入隊、出隊

3.1 kfifo_in

功能:buf中len長度數據寫入到fifo中

返回值:實際寫入長度

unsigned int __kfifo_in(struct __kfifo *fifo,const void *buf, unsigned int len)
{unsigned int l;l = kfifo_unused(fifo);        //判斷kfifo還有多少剩余空間if (len > l)len = l;kfifo_copy_in(fifo, buf, len, fifo->in);    //將數據拷貝到kfifo中fifo->in += len;               //設置寫入數量+lenreturn len;
}#define	kfifo_in(fifo, buf, n) \
({ \typeof((fifo) + 1) __tmp = (fifo); \typeof(__tmp->ptr_const) __buf = (buf); \unsigned long __n = (n); \const size_t __recsize = sizeof(*__tmp->rectype); \struct __kfifo *__kfifo = &__tmp->kfifo; \(__recsize) ?\__kfifo_in_r(__kfifo, __buf, __n, __recsize) : \__kfifo_in(__kfifo, __buf, __n); \
})

3.2 kfifo_out

功能:從fifo中獲取len長度數據到buf中

unsigned int __kfifo_out(struct __kfifo *fifo,void *buf, unsigned int len)
{len = __kfifo_out_peek(fifo, buf, len);    //fifo輸出數據到buffifo->out += len;                          //輸出數量+lenreturn len;
}#define	kfifo_out(fifo, buf, n) \
__kfifo_uint_must_check_helper( \
({ \typeof((fifo) + 1) __tmp = (fifo); \typeof(__tmp->ptr) __buf = (buf); \unsigned long __n = (n); \const size_t __recsize = sizeof(*__tmp->rectype); \struct __kfifo *__kfifo = &__tmp->kfifo; \(__recsize) ?\__kfifo_out_r(__kfifo, __buf, __n, __recsize) : \__kfifo_out(__kfifo, __buf, __n); \
}) \
)

4、動態申請、釋放內存

4.1 kfifo_alloc

功能:動態申請kfifo內存

返回值:0-成功,其他-失敗

int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,size_t esize, gfp_t gfp_mask)
{/** round up to the next power of 2, since our 'let the indices* wrap' technique works only in this case.*/size = roundup_pow_of_two(size);    //向上擴展為2的冪fifo->in = 0;fifo->out = 0;fifo->esize = esize;if (size < 2) {fifo->data = NULL;fifo->mask = 0;return -EINVAL;}fifo->data = kmalloc_array(esize, size, gfp_mask);    //動態申請內存if (!fifo->data) {fifo->mask = 0;return -ENOMEM;}fifo->mask = size - 1;return 0;
}#define kfifo_alloc(fifo, size, gfp_mask) \
__kfifo_int_must_check_helper( \
({ \typeof((fifo) + 1) __tmp = (fifo); \struct __kfifo *__kfifo = &__tmp->kfifo; \__is_kfifo_ptr(__tmp) ? \__kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \-EINVAL; \
}) \
)

注意:保證緩沖區大小為2的次冪,若不是,會向上取整為2的次冪(很重要)

4.2 kfifo_free

功能:釋放kfifo動態申請的內存

void __kfifo_free(struct __kfifo *fifo)
{kfree(fifo->data);        //釋放內存fifo->in = 0;fifo->out = 0;fifo->esize = 0;fifo->data = NULL;fifo->mask = 0;
}#define kfifo_free(fifo) \
({ \typeof((fifo) + 1) __tmp = (fifo); \struct __kfifo *__kfifo = &__tmp->kfifo; \if (__is_kfifo_ptr(__tmp)) \__kfifo_free(__kfifo); \
})

二、使用方法

使用kfifo的方式有兩種,動態申請和靜態定義。

3.1 動態申請

動態申請步驟如下:

① 包含頭文件 #include <linux/kfifo.h>

② 定義一個 struct kfifo 變量;

③ 使用 kfifo_alloc 申請內存空間;

④ 分別使用 kfifo_in、kfifo_out 執行入隊、出隊的操作;

⑤ 不再使用kfifo時,使用 kfifo_free 釋放申請的內存。

示例:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kfifo.h>//定義fifo存儲結構體
struct member {char name[32];char val;
};//定義fifo最大保存的元素個數
#define FIFO_MEMBER_NUM     64//定義kfifo
static struct kfifo stFifo;static int __init kfifo_demo_init(void)
{int ret = 0;int i;/* 1.申請fifo內存空間,空間大小最好為2的冪 */ret = kfifo_alloc(&stFifo, sizeof(struct member) * FIFO_MEMBER_NUM, GFP_KERNEL);if (ret) {printk(KERN_ERR "kfifo_alloc fail ret = %d\n", ret);return;}/* 2.入隊 */struct member stMember = {0}; for (i = 0; i < FIFO_MEMBER_NUM; i++) {snprintf(stMember.name, 32, "name%d", i);stMember.val = i;ret = kfifo_in(&stFifo, &stMember, sizeof(struct member));if (!ret) {printk(KERN_ERR "kfifo_in fail, fifo is full\n");}}/* 3.出隊 */for  (i = 0; i < FIFO_MEMBER_NUM; i++) {ret = kfifo_out_peek(&stFifo, &stMember, sizeof(struct member));        //讀,返回實際讀到長度(不修改out)ret = kfifo_out(&stFifo, &stMember, sizeof(struct member));             //讀,返回實際讀到長度(修改out)if (ret) {printk(KERN_INFO "kfifo_out stMember: name = %s, val=%d\n", stMember.name, stMember.val);} else {printk(KERN_ERR "kfifo_out fail, fifo is empty\n");}if (kfifo_is_empty(&stFifo)) {        //判斷fifo空printk(KERN_INFO "kfifo is empty!!!\n");break;}}/* 4.釋放 */kfifo_free(&stFifo);
}static void __exit kfifo_demo_exit(void)
{kfifo_free(&stFifo);
}module_init(kfifo_demo_init);
module_exit(kfifo_demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dong");

測試結果:

這種動態申請方式in、out都是以字節為單位。

3.2 靜態定義

靜態定義步驟如下:

① 包含頭文件 #include <linux/kfifo.h>

② 使用宏 DECLARE_KFIFO 靜態定義 fifo 變量;

③ 分別使用 kfifo_put、kfifo_get執行入隊、出隊的操作;

靜態定義不需要申請和釋放內存的步驟,出入隊函數也更精簡。

示例:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kfifo.h>//定義fifo存儲結構體
struct member {char name[32];char val;
};//定義fifo最大保存的元素個數,最好為2的冪
#define FIFO_MEMBER_NUM     64//靜態定義已經包含了緩存定義
DECLARE_KFIFO(stFifo, struct member, FIFO_MEMBER_NUM);static int __init kfifo_demo_init(void)
{int ret = 0;int i;/* 1.初始化  */INIT_KFIFO(stFifo);/* 2.入隊 */struct member stMember = {0}; for (i = 0; i < FIFO_MEMBER_NUM; i++) {snprintf(stMember.name, 32, "name%d", i);stMember.val = i;ret = kfifo_put(&stFifo, stMember);  //注意這里的元素變量名而不是指針if (!ret) {printk(KERN_ERR "kfifo_put fail, fifo is full\n");}}/* 3.出隊 */for  (i = 0; i < FIFO_MEMBER_NUM; i++) {ret = kfifo_get(&stFifo, &stMember); //注意這里傳入地址if (ret) {printk(KERN_INFO "kfifo_get stMember: name = %s, val=%d\n", stMember.name, stMember.val);} else {printk(KERN_ERR "kfifo_get fail, fifo is empty\n");}printk(KERN_INFO "kfifo: in = %d, out = %d\n", stFifo.kfifo.in, stFifo.kfifo.out);if (kfifo_is_empty(&stFifo)) {printk(KERN_INFO "kfifo is empty!!!\n");break;}}
}static void __exit kfifo_demo_exit(void)
{return;
}module_init(kfifo_demo_init);
module_exit(kfifo_demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dong");

測試結果:?

示例中靜態定義的in、out是以結構體為單位,64次入隊fifo中就會有64個結構體元素。

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

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

相關文章

nginx修改網站默認根目錄及發布(linux、centos、ubuntu)openEuler軟件源repo站點

目錄 安裝nginx配置nginx其它權限配置 安裝nginx dnf install -y nginx配置nginx whereis nginxcd /etc/nginx llcd conf.d touch vhost.conf vim vhost.conf 命令模式下輸入:set nu或:set number可以顯示行號 復制如下內容&#xff1a; server {listen 80;server_name…

【0294】Postgres內核 dynahash 之 hash_search 實現原理

相關文章: 【0289】Postgres內核之哈希表(Hash Tables) 【0290】Postgres內核之dynahash(動態哈希表,dynamic hash tables)(概念篇) 【0291】Postgres內核之dynahash table 創建 【0292】Postgres內核源碼之dynahash 插入entry實現 【0293】Postgres內核之創建 dynahas…

ESP32 通過藍牙顯示歌詞代碼示例

通過藍牙協議播放音樂&#xff0c;有的時候需要顯示歌詞&#xff0c;這里就是a2dp庫獲取了歌詞 值得注意的是要想正確獲取到歌詞&#xff0c;必須打開各種播放器的字幕&#xff08;歌詞&#xff09;開關 本項目用了三個開源庫 a2dp&#xff0c;tft_espi,xfont. a2dp &#x…

基于python實現的監聽服務接口是否正常,發送異常消息到釘釘群

獲取釘釘機器人 創建釘釘群組(要求至少三個成員)進入群組 設置>機器人>添加機器人選擇自定義機器人 按照要求填寫完獲取到 Webhook的鏈接 實現代碼 from time import sleep import requests import json from datetime import datetime import logging# 配置日志記錄的…

數據結構第11節: B樹

B樹是一種自平衡的樹數據結構&#xff0c;它能夠保持數據排序&#xff0c;并且在插入、刪除和查找操作中具有對數時間復雜度。B樹廣泛應用于文件系統、數據庫和索引中&#xff0c;因為它們可以有效地處理大量數據。 B樹的特點&#xff1a; 所有葉子節點都位于同一層。每個節點…

【】AI八股-神經網絡相關

Deep-Learning-Interview-Book/docs/深度學習.md at master amusi/Deep-Learning-Interview-Book GitHub 網上相關總結&#xff1a; 小菜雞寫一寫基礎深度學習的問題&#xff08;復制大佬的&#xff0c;自己復習用&#xff09; - 知乎 (zhihu.com) CV面試問題準備持續更新貼 …

.net 調用海康SDK的跨平臺解決方案

??歡迎點贊 :?? 收藏 ?留言 ?? 如有錯誤敬請指正,賜人玫瑰,手留余香!??本文作者:由webmote 原創??作者格言:新的征程,我們面對的不僅僅是技術還有人心,人心不可測,海水不可量,唯有技術,才是深沉黑夜中的一座閃爍的燈塔序言 上2篇海康SDK使用以及常見的坑…

PCL 點云PFH特征描述子

點云PFH特征描述子 一、概述1.1 概念1.2 算法原理一、代碼實現二、結果示例一、概述 1.1 概念 點特征直方圖PFH(Point Feature Histograms)描述子:用于表示點云中每個點的局部幾何形狀信息,它是一種直方圖描述子,包括了點云的法線方向和曲率信息,PFH描述子可以幫助區分不同…

深入Django(八)

掌握Django的管理后臺 引言 在前七天的教程中&#xff0c;我們介紹了Django的基礎架構、模型、視圖、模板、URL路由、表單系統以及數據庫遷移。今天&#xff0c;我們將深入了解Django的管理后臺&#xff0c;這是一個功能強大的內置管理界面&#xff0c;用于創建、更新、查看和…

【JavaEE精煉寶庫】文件操作(1)——基本知識 | 操作文件——打開實用性編程的大門

目錄 一、文件的基本知識1.1 文件的基本概念&#xff1a;1.2 樹型結構組織和目錄&#xff1a;1.3 文件路徑&#xff08;Path&#xff09;&#xff1a;1.4 二進制文件 VS 文本文件&#xff1a;1.5 其它&#xff1a; 二、Java 操作文件2.1 方法說明&#xff1a;2.2 使用演示&…

QT面試筆記總計

一 Qt 保證多線程安全? 使互斥鎖保證多線程安全性。QMutex類、。使用讀寫鎖保證多線程安全性&#xff0c;QReadWriteLock。使用信號和槽機制保證多線程安全性。使用顯示切換保證多線程安全性。QTread類。 Qt 中的事件與信號的區別? 事件與信號的實現機制不同&#xff1b;事…

HCIA綜合實驗

學習新思想&#xff0c;爭做新青年。今天學習的是HCIA綜合實驗&#xff01; 實驗拓撲 實驗需求 總部&#xff1a; 1、除了SW8 SW9是三層交換機&#xff0c;其他交換機均為2層交換機。 2、GW為總部的出口設備&#xff0c;使用單臂路由技術&#xff0c;VLAN10,20,100的網關都在GW…

ERROR: “armeabi-v7a“ not supported for HarmonyOS

IDE 從 devecostudio-mac-4.1.3.700 升級至 devecostudio-mac-5.0.3.403 后拋出了如下異常: ERROR: "armeabi-v7a" not supported for HarmonyOS. 解決辦法 一.entry/build-profile.json5 需 entry/build-profile.json5 的 abiFilters 中移除 "armeabi-v7a&qu…

計算機網絡體系結構詳解:協議與分層

在學習計算機網絡時&#xff0c;理解網絡協議與分層體系結構是至關重要的。本文將詳細介紹這些概念&#xff0c;幫助基礎小白快速入門。 1. 什么是網絡協議 網絡協議是計算機網絡中用于數據交換的規則和標準。這些規則規定了數據格式、時序以及發送和接收數據時的動作。網絡協…

Unity3D瓦片地圖輔助定位工具

介紹 該工具用于TileMap的瓦片輔助定位&#xff0c;通過鍵盤或鼠標按瓦片尺寸0到1的比例作為單次移動值移動定位點游戲對象。當采用定位點游戲對象映射瓦片時&#xff0c;可使用該工具來移動定位點游戲對象&#xff0c;在新版本Unity3D的TileMap編輯器中可使用GameObject Brush…

基于java+springboot+vue實現的流浪動物管理系統(文末源碼+Lw)277

摘 要 在如今社會上&#xff0c;關于信息上面的處理&#xff0c;沒有任何一個企業或者個人會忽視&#xff0c;如何讓信息急速傳遞&#xff0c;并且歸檔儲存查詢&#xff0c;采用之前的紙張記錄模式已經不符合當前使用要求了。所以&#xff0c;對流浪動物信息管理的提升&…

【React】React18 Hooks之useState

目錄 useState案例1&#xff08;直接修改狀態&#xff09;案例2&#xff08;函數式更新&#xff09;案例3&#xff08;受控表單綁定&#xff09;注意事項1&#xff1a;set函數不會改變正在運行的代碼的狀態注意事項2&#xff1a;set函數自動批量處理注意事項3&#xff1a;在下次…

實現基于Spring Security的權限管理系統

實現基于Spring Security的權限管理系統 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在現代Web應用中&#xff0c;權限管理系統是至關重要的組成部分。通過…

[數據集][目標檢測]護目鏡檢測數據集VOC+YOLO格式888張1類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;888 標注數量(xml文件個數)&#xff1a;888 標注數量(txt文件個數)&#xff1a;888 標注類別…

ORB 特征點提取

FAST關鍵點 選取像素p&#xff0c;假設它的亮度為Ip&#xff1b; . 設置一個閾值T&#xff08;比如Ip的20%&#xff09;&#xff1b; 以像素p為中心&#xff0c;選取半徑為3的圓上的16個像素點&#xff1b; 假如選取的圓上&#xff0c;有連續的N個點的亮度大于IpT或小于…