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。 |
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个结构体元素。
相关文章:

linux驱动编程 - kfifo先进先出队列
简介: kfifo是Linux Kernel里面的一个 FIFO(先进先出)数据结构,它采用环形循环队列的数据结构来实现,提供一个无边界的字节流服务,并且使用并行无锁编程技术,即当它用于只有一个入队线程和一个出…...

JS 四舍五入使用整理
一、Number.toFixed() 把数字转换为字符串,结果的小数点后有指定位数的数字,重点返回的数据类型为字符串 toFixed() 方法将一个浮点数转换为指定小数位数的字符串表示,如果小数位数高于数字,则使用 0 来填充。 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。…...

上万组风电,光伏,用户负荷数据分享
上万组风电,光伏,用户负荷数据分享 可用于风光负荷预测等研究 获取链接🔗 https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取码:381i 获取链接🔗 https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取…...

在物联网快速发展的趋势下,Java 怎样优化对低功耗、资源受限的边缘设备的支持,保障物联网应用的稳定运行?
在物联网快速发展的趋势下,Java可以通过以下方式优化对低功耗、资源受限的边缘设备的支持,以保障物联网应用的稳定运行: 精简Java运行环境:针对边缘设备的资源限制,可以使用精简型的Java运行环境,避免不必要…...

java-HashSet 源码分析 1
## 深入分析 Java 中的 HashSet 源码 HashSet 是 Java 集合框架中的一个重要类,它基于哈希表实现,用于存储不重复的元素。HashSet 允许 null 元素,并且不保证元素的顺序。本文将详细分析 HashSet 的源码,包括其数据结构、构造方法…...

K8S 部署 EFK
安装说明 系统版本为 Centos7.9 内核版本为 6.3.5-1.el7 K8S版本为 v1.26.14 ES官网 开始安装 本次安装使用官方ECK方式部署 EFK,部署的是当前的最新版本。 在 Kubernetes 集群中部署 ECK 安装自定义资源 如果能打开这个网址的话直接用这个命令安装,打不开的话…...

AI Earth应用—— 在线使用sentinel数据VV和VH波段进行水体提取分析(昆明抚仙湖、滇池为例)
AI Earth 本文的主要目的就是对水体进行提取,这里,具体的操作步骤很简单基本上是通过,首页的数据检索,选择需要研究的区域,然后选择工具箱种的水体提取分析即可,剩下的就交给阿里云去处理,结果如下: 这是我所选取的一景影像: 详情 卫星: Sentinel-1 级别: 1 …...

基于Hadoop平台的电信客服数据的处理与分析③项目开发:搭建基于Hadoop的全分布式集群---任务9:HBase的安装和部署
任务描述 任务内容为HBase的安装部署与测试。 任务指导 HBase集群需要整个集群所有节点安装的HBase版本保持一致,并且拥有相同的配置 具体配置步骤如下: 1. 解压缩HBase的压缩包 2. 配置HBase的环境变量 3. 修改HBase的配置文件,HBase…...

go语言day09 通道 协程的死锁
Go语言学习——channel的死锁其实没那么复杂 - JackieZheng - 博客园 (cnblogs.com) 目录 通道 创建通道 1)无缓冲通道 2)有缓冲通道 通道的使用 1) 值从通道入口进 2) 值从通道出口出 信道死锁: 0)死锁现场0 1)死…...

黑马的ES课程中的不足
在我自己做项目使用ES的时候,发现了黑马没教的方法,以及一些它项目的小问题 搜索时的匹配方法 这个boolQuery().should 我的项目是通过文章的标题title和内容content来进行搜索 但是黑马它的项目只用了must 如果我们的title和content都用must&#x…...

STM32 中断编程入门
目录 一、中断系统 1、中断的原理 2、中断类型 外部中断 定时器中断 DMA中断 3、中断处理函数 中断标志位清除 中断服务程序退出 二、实际应用 中断控制LED 任务要求 代码示例 中断控制串口通信 任务要求1 代码示例 任务要求2 代码示例 总结 学习目标&…...

使用maven搭建一个SpingBoot项目
1.首先创建一个maven项目 注意选择合适的jdk版本 2.添加依赖 2.在pom.xml中至少添加依赖 spring-boot-starter-web 依赖,目的是引入Tomcat,以及SpringMVC等,使项目具有web功能。 <!-- 引入 包含tomcat,SpringMVC,…...

使用 HTTPS 已成为网站的标配了
网站使用HTTPS的原因 背景:十年前,HTTPS并不普遍,但随着网络安全意识的提高,现在已成为网站标配。 网站升级到HTTPS的动机 安全问题:HTTP缺乏安全机制,易被窃取和篡改数据。例如,电信运营商劫…...

前后端分离Nginx
背景 旧的部署方式是将前端代码打包进后端包的resource server {listen 80;listen 443 ssl;server_name xxx.test.com;location / {proxy_pass http://xxx.test.com;} }后端:https:// xxx.test.com/simcard/querySimcard 前端:https:// x…...

【简单讲解下Tauri】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...

mac上挂载linux目录
在 macOS 上挂载 CentOS 目录步骤: 在挂载前确保 macOS 和 CentOS 在同一个局域网内,并且可以相互访问。如果有网络配置问题,可能会导致挂载失败或连接被拒绝的错误。 要在 macOS 上将 CentOS 的 /disk2/go 目录通过 NFS 挂载到 /Users/zon…...

Linux系统的服务——以Centos7为例
一、Linux系统的服务简介 服务是向外部提供对应功能的进程,其运行在系统后台,能够7*24小时持续不断的提供外界随时发来的服务请求,且服务进程常驻在内存中,具有固定的端口号,通过端口号就能找到服务内容。 提供服务的一…...

Numpy矩阵运算
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl Numpy概述 Numpy是Python的一个开源数值计算扩展库,主要用于存储和处理大型多维数组和矩阵,并且提供了大量的数学函数来操作这些数组。Numpy是Pytho…...

Spring容器Bean之XML配置方式
一、首先看applicationContext.xml里的配置项bean 我们采用xml配置文件的方式对bean进行声明和管理,每一个bean标签都代表着需要被创建的对象并通过property标签可以为该类注入其他依赖对象,通过这种方式Spring容器就可以成功知道我们需要创建那些bean实…...

【Rust入门】生成随机数
文章目录 前言随机数库rand添加rand库到我们的工程生成一个随机数示例代码 总结 前言 在编程中,生成随机数是一种常见的需求,无论是用于数据分析、游戏开发还是模拟实验。Rust提供了强大的库来帮助我们生成随机数。在这篇文章中,我们将通过一…...

普通Java工程如何在代码中引用docker-compose.yml中的environment值
文章目录 一、概述二、常规做法1. 数据库配置分离2. 代码引用配置3. 编写启动类4. 支持打包成可执行包5. 支持可执行包打包成docker镜像6. docker运行 三、存在问题分析四、改进措施1. 包含environment 变量的编排文件2. 修改读取配置文件方式3. 为什么可以这样做 五、运行效果…...

微观特征轮廓尺寸测量:光学3D轮廓仪、共焦显微镜与台阶仪的应用
随着科技进步,显微测量仪器以满足日益增长的微观尺寸测量需求而不断发展进步。多种高精度测量仪器被用于微观尺寸的测量,其中包括光学3D表面轮廓仪(白光干涉仪)、共聚焦显微镜和台阶仪。有效评估材料表面的微观结构和形貌…...

Rust开发环境搭建
Rust开发环境搭建 环境 rust: 1.79.0(2024-06-13)1. Rustup下载器在线安装 windows: https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe unix: curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh2. R…...

图文识别0难度上手~基于飞浆对pdf简易ocr并转txt
前言 本篇pdf适用windows对视觉识别0基础的的纯小白用户。大佬请绕道~~ 注意: 本项目pdf的ocr对于表格、画图文字,水印等干扰没做任何处理,因此希望各位使用该功能的pdf尽量不要含有这些干扰项,以免影响翻译效果。 流程 1.构建…...

FFmpeg常用命令手册
官方文档:ffmpeg Documentation 常规选项 -i input_url 输入文件或者输入流的路径 Main 选项 -f fmt (input/output) 强制指定输入或输出文件的格式, 常见的格式名称包括flv,mp4、hls、mpegts、avi、mov -c[:stream_specifier] codec (i…...

CTF入门知识点
CTF知识点 md5函数 <?php$a 123;echo md5($a,true); ?> 括号中true显示输出二进制 替换成false显示输出十六进制绕过 ffifdyop 这个字符串被 md5 哈希了之后会变成 276f722736c95d99e921722cf9ed621c,这个字符串前几位刚好是 or 6 而 Mysql 刚好又会把 …...

Leetcode 完美数
1.题目要求: 对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」。给定一个 整数 n, 如果是完美数,返回 true;否则返回 false。示例 1:输入:num 28 输出&a…...

springboot中的定时任务编写
第1部分:引言 1.1 定时任务的重要性 在现代软件开发中,定时任务是应用程序自动化和运维效率的关键组成部分。无论是数据备份、系统健康检查、定期报告生成,还是用户活动触发的自动化流程,定时任务都扮演着不可或缺的角色。它们确…...

第100+14步 ChatGPT学习:R实现随机森林分类
基于R 4.2.2版本演示 一、写在前面 有不少大佬问做机器学习分类能不能用R语言,不想学Python咯。 答曰:可!用GPT或者Kimi转一下就得了呗。 加上最近也没啥内容写了,就帮各位搬运一下吧。 二、R代码实现随机森林分类 ÿ…...

C#面 :ASP.Net Core中有哪些异常处理的方案?
在 ASP.NET Core中,有多种异常处理方案可供选择。以下是其中几种常见的异常处理方案: 中间件异常处理: ASP.NET Core提供了一个中间件来处理全局异常。通过在Startup类的Configure方法中添加UseExceptionHandler中间件,可以捕获…...