IMX6LL|linux设备驱动模型
linux设备驱动模型
为什么需要设备驱动模型
- 早期内核(2.4之前)没有统一的设备驱动模型,但照样可以用
- 2.4~2.6期间使用devfs,挂载在/dev目录。
- 需要在内核驱动中创建设备文件(devfs_register),命名死板
- 2.6以后使用sysfs,挂载在/sys目录
- 将设备分类、分层次统一进行管理
- 配合udev/mdev守护进程动态创建设备文件,命令规则自由制定
sysfs概述
linux系统通过sysfs体现出设备驱动模型
- sysfs是一个虚拟文件系统(类似proc文件系统)
- 目录对应的inode节点会记录基本驱动对象(kobject),从而将系统中的设备组成层次结构
- 用户可以读写目录下的不同文件来配置驱动对象(kobject)的不同属性
设备驱动模型基本元素
-
kobject:sysfs中的一个目录,常用来表示基本驱动对象,不允许发送消息到用户空间
-
kset:sysfs中的一个目录,常用来管理kobject,允许发送消息到用户空间
-
kobj_type:目录下属性文件的操作接口
驱动模型一
kset可批量管理kobject
kobject无法批量管理kobject
驱动模型二
- 上层kobject节点无法遍历查找下层kobject
kobject
sysfs中每一个目录都对应一个kobject
include/linux/kobject.h
struct kobject {//用来表示该kobject的名称const char *name;//链表节点struct list_head entry;//该kobject的上层节点,构建kobject之间的层次关系struct kobject *parent;//该kobject所属的kset对象,用于批量管理kobject对象struct kset *kset;//该Kobject的sysfs文件系统相关的操作和属性struct kobj_type *ktype;//该kobject在sysfs文件系统中对应目录项struct kernfs_node *sd; /* sysfs directory entry *///该kobject的引用次数struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASEstruct delayed_work release;
#endif//记录内核对象的初始化状态unsigned int state_initialized:1;//表示该kobject所代表的内核对象有没有在sysfs建立目录unsigned int state_in_sysfs:1;unsigned int state_add_uevent_sent:1;unsigned int state_remove_uevent_sent:1;unsigned int uevent_suppress:1;
};
kset
struct kset {//用来将起中的object对象构建成链表struct list_head list;//自旋锁spinlock_t list_lock;//当前kset内核对象的kobject变量struct kobject kobj;//定义了一组函数指针,当kset中的某些kobject对象发生状态变化需要通知用户空间时,调用其中的函数来完成const struct kset_uevent_ops *uevent_ops;
}
kobj_type
struct kobj_type {//销毁kobject对象时调用void (*release)(struct kobject *kobj);//kobject对象属性文件统一操作接口const struct sysfs_ops *sysfs_ops;//kobject默认属性文件的名字、"文件具体操作接口"struct attribute **default_attrs; const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);const void *(*namespace)(struct kobject *kobj);void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
kobject:驱动的基石
- 构建一个kobject对象
- 构建一个sysfs中的目录项(kernfs_node)
- 把他们关联起来
重点
- 关注sysfs目录项与kobject对象的关联过程
- 关注kobject对象默认的属性文件操作接口
kobject_create_and_add()函数
掌握这一个函数即可
lib/kobject.c
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{struct kobject *kobj;int retval;/*创建并初始化一个kobject对象*/kobj = kobject_create();if (!kobj)return NULL;/*sysfs创建一个目录项并与kobject对象关联*/retval = kobject_add(kobj, parent, "%s", name);if (retval) {pr_warn("%s: kobject_add error: %d\n", __func__, retval);kobject_put(kobj);kobj = NULL;}return kobj;
}
kobject_create()函数
lib/kobject.c
struct kobject *kobject_create(void)
{struct kobject *kobj;/*动态申请内存,存放kobject对象*/kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);if (!kobj)return NULL;kobject_init(kobj, &dynamic_kobj_ktype);return kobj;
}
static struct kobj_type dynamic_kobj_ktype = {.release = dynamic_kobj_release,.sysfs_ops = &kobj_sysfs_ops,
};
const struct sysfs_ops kobj_sysfs_ops = {.show = kobj_attr_show,.store = kobj_attr_store,
};
kobject_init()函数
lib/kobject.c
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
...kobject_init_internal(kobj);/*设置目录属性文件的操作接口*/kobj->ktype = ktype;return;
...
}
kobject_init_internal()函数
lib/kobject.c
static void kobject_init_internal(struct kobject *kobj)
{if (!kobj)return;\/*将kobject的引用计数设置为1*/kref_init(&kobj->kref);/*初始化链表节点*/INIT_LIST_HEAD(&kobj->entry);/*该kobject对象还没和sysfs目录项关联*/kobj->state_in_sysfs = 0;kobj->state_add_uevent_sent = 0;kobj->state_remove_uevent_sent = 0;/*kobject对象的初始化标志*/kobj->state_initialized = 1;
}
kobject_add()函数
lib/kobject.c
retval = kobject_add(kobj, parent, “%s”, name);
int kobject_add(struct kobject *kobj, struct kobject *parent,const char *fmt, ...)
{va_list args;int retval;
.../*获取第一个可变参数,可变参数函数的实现与函数传参的栈结构有关*/va_start(args, fmt);retval = kobject_add_varg(kobj, parent, fmt, args);va_end(args);
...return retval;
}
kobject_add_varg()函数
lib/kobject.c
static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,struct kobject *parent,const char *fmt, va_list vargs)
{int retval;retval = kobject_set_name_vargs(kobj, fmt, vargs);if (retval) {pr_err("kobject: can not set name properly!\n");return retval;}/*第一次设置kobj的parent指针*/kobj->parent = parent;return kobject_add_internal(kobj);
}
kobject_set_name_vargs()函数
lib/kobject.c
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,va_list vargs)
{const char *s;.../*参数格式化打印到s字符串中*/s = kvasprintf_const(GFP_KERNEL, fmt, vargs);.../*设置kobject对象的名称*/kobj->name = s;...
}
kobject_add_internal()函数
lib/kobject.c
static int kobject_add_internal(struct kobject *kobj)
{struct kobject *parent;...parent = kobject_get(kobj->parent);if (kobj->kset) {/*如果parent为空,parent设置为kobj->kset->kobj*/if (!parent)parent = kobject_get(&kobj->kset->kobj);/*把该kobject加入到kset链表的末尾*/kobj_kset_join(kobj);/*第二次设置kobj的parent指针*/kobj->parent = parent;}...error = create_dir(kobj);...kobj->state_in_sysfs = 1;...
}
create_dir()函数
lib/kobject.c
static int create_dir(struct kobject *kobj)
{const struct kobj_ns_type_operations *ops;int error;error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));...
}
sysfs_create_dir_ns()函数
fs/sysfs/dir.c
int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
{struct kernfs_node *parent, *kn;kuid_t uid;kgid_t gid;BUG_ON(!kobj);if (kobj->parent)/*获取上一层节点的目录项*/parent = kobj->parent->sd;else/*设置上一层节点的目录项为sysfs根目录*/parent = sysfs_root_kn;if (!parent)return -ENOENT;kn = kernfs_create_dir_ns(parent, kobject_name(kobj),S_IRWXU | S_IRUGO | S_IXUGO, uid, gid,kobj, ns);.../*kobj对象关联sysfs目录项*/kobj->sd = kn;return 0;
}
kernfs_create_dir_ns()函数
struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,const char *name, umode_t mode,kuid_t uid, kgid_t gid,void *priv, const void *ns)
{struct kernfs_node *kn;int rc;/* allocate */kn = kernfs_new_node(parent, name, mode | S_IFDIR,uid, gid, KERNFS_DIR);.../*sysfs目录项关联kobject对象*/kn->priv = priv;...
}
kernfs_new_node()函数
struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,const char *name, umode_t mode,kuid_t uid, kgid_t gid,unsigned flags)
{struct kernfs_node *kn;kn = __kernfs_new_node(kernfs_root(parent),name, mode, uid, gid, flags);if (kn) {kernfs_get(parent);kn->parent = parent;}return kn;
}
kobj_type:用户空间的法宝
- 为kobject对象构建多个属性文件
- 为每个属性文件设置具体操作接口
- vfs的inode对象与sysfs的kernfs_node对象的绑定过程
重点
- 关注属性文件具体操作接口的赋值过程
- 关注open()、read()、write函数的底层机制
第一阶段:属性文件操作接口赋值
sysfs_create_group()函数
fs/sysfs/group.c
创建接口文件,并且绑定接口
int sysfs_create_group(struct kobject *kobj,const struct attribute_group *grp)
{return internal_create_group(kobj, 0, grp);
}
-
attribute_group结构体:
include/linux/sysfs.h
struct attribute_group {const char *name;umode_t (*is_visible)(struct kobject *,struct attribute *, int);umode_t (*is_bin_visible)(struct kobject *,struct bin_attribute *, int);struct attribute **attrs;struct bin_attribute **bin_attrs;
};
-
struct attribute结构体:
include/linux/sysfs.h
struct attribute {const char *name;umode_t mode;
};
- kobj_attribute结构体
struct kobj_attribute {struct attribute attr;ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,char *buf);ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count);
};
internal_create_group()函数
fs/sysfs/group.c
tatic int internal_create_group(struct kobject *kobj, int update,const struct attribute_group *grp)
{struct kernfs_node *kn;kuid_t uid;kgid_t gid;int error;...if (grp->name)...elsekn = kobj->sd;...error = create_files(kn, kobj, uid, gid, grp, update);...
}
create_files()函数
fs/sysfs/group.c
static int create_files(struct kernfs_node *parent, struct kobject *kobj,kuid_t uid, kgid_t gid,const struct attribute_group *grp, int update)
{struct attribute *const *attr;struct bin_attribute *const *bin_attr;int error = 0, i;if (grp->attrs) {for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {umode_t mode = (*attr)->mode;...error = sysfs_add_file_mode_ns(parent, *attr, false,mode, uid, gid, NULL);...}...
}
sysfs_add_file_mode_ns()函数
fs/sysfs/file.c
int sysfs_add_file_mode_ns(struct kernfs_node *parent,const struct attribute *attr, bool is_bin,umode_t mode, kuid_t uid, kgid_t gid, const void *ns)
{struct lock_class_key *key = NULL;const struct kernfs_ops *ops;struct kernfs_node *kn;loff_t size;if (!is_bin) {struct kobject *kobj = parent->priv;/*kobj_sysfs_ops*/const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;...if (sysfs_ops->show && sysfs_ops->store) {if (mode & SYSFS_PREALLOC)ops = &sysfs_prealloc_kfops_rw;elseops = &sysfs_file_kfops_rw;else if...}...kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,size, ops, (void *)attr, ns, key);...
}
- kernfs_ops节点的操作函数
static const struct kernfs_ops sysfs_file_kfops_rw = {.seq_show = sysfs_kf_seq_show,.write = sysfs_kf_write,
};
__kernfs_create_file()函数
struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,const char *name,umode_t mode, kuid_t uid, kgid_t gid,loff_t size,const struct kernfs_ops *ops,void *priv, const void *ns,struct lock_class_key *key)
{struct kernfs_node *kn;unsigned flags;int rc;flags = KERNFS_FILE;kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG,uid, gid, flags);if (!kn)return ERR_PTR(-ENOMEM);/*操作接口赋值*/kn->attr.ops = ops;kn->attr.size = size;kn->ns = ns;/*文件属性赋值*/kn->priv = priv;if (ops->seq_show)kn->flags |= KERNFS_HAS_SEQ_SHOW;...
}
第二阶段:open()\read()\write()的底层机制
kernfs_init_inode()函数
static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
{kernfs_get(kn);/*sysfs的kernels_node赋值给vfs的inode*/inode->i_private = kn;inode->i_mapping->a_ops = &kernfs_aops;inode->i_op = &kernfs_iops;inode->i_generation = kn->id.generation;set_default_inode_attr(inode, kn->mode);kernfs_refresh_inode(kn, inode);/* 判断sysfs的kernels_node类型 */switch (kernfs_type(kn)) {case KERNFS_DIR:inode->i_op = &kernfs_dir_iops;inode->i_fop = &kernfs_dir_fops;if (kn->flags & KERNFS_EMPTY_DIR)make_empty_dir_inode(inode);break;case KERNFS_FILE:inode->i_size = kn->attr.size;/*文件的操作接口*/inode->i_fop = &kernfs_file_fops;break;case KERNFS_LINK:inode->i_op = &kernfs_symlink_iops;break;default:BUG();}unlock_new_inode(inode);
}
const struct file_operations kernfs_file_fops = {.read = kernfs_fop_read,.write = kernfs_fop_write,.llseek = generic_file_llseek,.mmap = kernfs_fop_mmap,.open = kernfs_fop_open,.release = kernfs_fop_release,.poll = kernfs_fop_poll,.fsync = noop_fsync,
};
kernfs_fop_open()函数
static int kernfs_fop_open(struct inode *inode, struct file *file)
{struct kernfs_node *kn = inode->i_private;struct kernfs_open_file *of;...of = kzalloc(sizeof(struct kernfs_open_file), GFP_KERNEL);.../*sysfs中文件的kernfs_node赋值给of->kn*/of->kn = kn;/*进程的struct file赋值给of->file/of->file = file;...if (ops->seq_show)error = seq_open(file, &kernfs_seq_ops);.../*struct file的私有指针赋值给of->seq_file */of->seq_file = file->private_data;/*of赋值给of->seq_file->private*/of->seq_file->private = of;...}
static const struct seq_operations kernfs_seq_ops = {.start = kernfs_seq_start,.next = kernfs_seq_next,.stop = kernfs_seq_stop,.show = kernfs_seq_show,
};
seq_open
int seq_open(struct file *file, const struct seq_operations *op)
{struct seq_file *p;WARN_ON(file->private_data);p = kmem_cache_zalloc(seq_file_cache, GFP_KERNEL);if (!p)return -ENOMEM;file->private_data = p;...p->op = op;...
}
kernfs_fop_read()函数
static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf,size_t count, loff_t *ppos)
{struct kernfs_open_file *of = kernfs_of(file);if (of->kn->flags & KERNFS_HAS_SEQ_SHOW)return seq_read(file, user_buf, count, ppos);elsereturn kernfs_file_direct_read(of, user_buf, count, ppos);
}
kernfs_of()函数
static struct kernfs_open_file *kernfs_of(struct file *file)
{return ((struct seq_file *)file->private_data)->private;
}
seq_read()函数
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{struct seq_file *m = file->private_data;...err = m->op->show(m, p);...err = copy_to_user(buf, m->buf, n);...
}
kernfs_seq_show()函数
static int kernfs_seq_show(struct seq_file *sf, void *v)
{struct kernfs_open_file *of = sf->private;...return of->kn->attr.ops->seq_show(sf, v);
}
sysfs_kf_seq_show()函数
static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
{struct kernfs_open_file *of = sf->private;struct kobject *kobj = of->kn->parent->priv;const struct sysfs_ops *ops = sysfs_file_ops(of->kn);ssize_t count;char *buf;count = seq_get_buf(sf, &buf);if (count < PAGE_SIZE) {seq_commit(sf, -1);return 0;}memset(buf, 0, PAGE_SIZE);/** Invoke show(). Control may reach here via seq file lseek even* if @ops->show() isn't implemented.*/if (ops->show) {count = ops->show(kobj, of->kn->priv, buf);if (count < 0)return count;}/** The code works fine with PAGE_SIZE return but it's likely to* indicate truncated result or overflow in normal use cases.*/if (count >= (ssize_t)PAGE_SIZE) {printk("fill_read_buffer: %pS returned bad count\n",ops->show);/* Try to struggle along */count = PAGE_SIZE - 1;}seq_commit(sf, count);return 0;
}
sysfs_file_ops()函数
static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
{struct kobject *kobj = kn->parent->priv;if (kn->flags & KERNFS_LOCKDEP)lockdep_assert_held(kn);return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
}
seq_get_buf()函数
static inline size_t seq_get_buf(struct seq_file *m, char **bufp)
{BUG_ON(m->count > m->size);if (m->count < m->size)*bufp = m->buf + m->count;else*bufp = NULL;return m->size - m->count;
}
kobj_attr_show()函数
static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
{struct kobj_attribute *kattr;ssize_t ret = -EIO;/*根据结构体成员的内存地址获取结构体的地址*/kattr = container_of(attr, struct kobj_attribute, attr);if (kattr->show)ret = kattr->show(kobj, kattr, buf);return ret;
}
设备驱动模型实验1-kobject点灯
实验思路
内核模块+led驱动+kobject+kobj_attribute
内核模块
- 动态加载功能
led驱动
- 控制硬件led
kobject
- 在/sys创建目录项
kobj_attribute
- 为kobject对象的属性文件提供独有的读写接口
kset:驱动的骨架
kobject的容器,体现设备驱动的层次关系
kset_create_and_add()函数
lib/kobject.c
struct kset *kset_create_and_add(const char *name,
const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)
{struct kset *kset;int error;kset = kset_create(name, uevent_ops, parent_kobj);if (!kset)return NULL;error = kset_register(kset);if (error) {kfree(kset);return NULL;}return kset;
}
kset_create()函数
lib/kobject.c
static struct kset *kset_create(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)
{struct kset *kset;int retval;kset = kzalloc(sizeof(*kset), GFP_KERNEL);if (!kset)return NULL;retval = kobject_set_name(&kset->kobj, "%s", name);if (retval) {kfree(kset);return NULL;}/*注册消息发送接口*/kset->uevent_ops = uevent_ops;kset->kobj.parent = parent_kobj;kset->kobj.ktype = &kset_ktype;kset->kobj.kset = NULL;return kset;
}
kset_init()函数
lib/kobject.c
void kset_init(struct kset *k)
{kobject_init_internal(&k->kobj);INIT_LIST_HEAD(&k->list);spin_lock_init(&k->list_lock);
}
kset_register()函数
lib/kobject.c
int kset_register(struct kset *k)
{int err;if (!k)return -EINVAL;kset_init(k);err = kobject_add_internal(&k->kobj);if (err)return err;/*发送驱动模型消息到应用层*/kobject_uevent(&k->kobj, KOBJ_ADD);return 0;
}
相关文章:

IMX6LL|linux设备驱动模型
linux设备驱动模型 为什么需要设备驱动模型 早期内核(2.4之前)没有统一的设备驱动模型,但照样可以用2.4~2.6期间使用devfs,挂载在/dev目录。 需要在内核驱动中创建设备文件(devfs_register),命名死板 2.6以后使用sys…...

2023年的技术总结和工作反思
一、回顾2023年 回顾自己的2023年,还是发生了很多的变化。在大学毕业,就来到了芯翼参加工作,在这里也遇到了很多的前辈和小伙伴,收获工作的同时也收获了友情。但是,随着公司发展战略的变化,公司的人员架构…...

Stable Diffusion中的Embeddings
什么是Embeddings? Embeddings是一种数学技术,它允许我们将复杂的数据(如文本或图像)转换为数值向量。这些向量是高维空间中的点,可以捕捉数据的关键特征和属性。在文本处理中,例如,embeddings可…...

如何快速打开github
作为一个资深码农,怎么能不熟悉全球最大的同性交友社区——github呢,但头疼的是github有时能打开,有时打不开,这是怎么回事? 其实问题出在github.com解析DNS上,并不是需要FQ。下面提供一个方法,…...

【sql/python】表中某列值以列表聚合
需求背景: 有一个表含有两个字段 “ID”,“VALUE” 1,香蕉 1,苹果 2,橘子 3,香蕉 3,苹果 3,橘子 目标要求:将每个ID的VALUE列聚合成一个字符串列表 “ID”,“VALUE” 1,[香蕉,苹果] 2,[橘子] 3,[香蕉,苹果,橘子] 一、SQL使用 LISTAGG函数聚合方式 ---将…...

大模型实战营Day6 作业
基础作业 使用 OpenCompass 评测 InternLM2-Chat-7B 模型在 C-Eval 数据集上的性能 环境配置 conda create --name opencompass --clone/root/share/conda_envs/internlm-base source activate opencompass git clone https://github.com/open-compass/opencompass cd openco…...

C#,入门教程(20)——列表(List)的基础知识
上一篇: C#,入门教程(19)——循环语句(for,while,foreach)的基础知识https://blog.csdn.net/beijinghorn/article/details/124060844 List顾名思义就是数据列表,区别于数据数组(arr…...

【蓝桥杯日记】复盘篇一:深入浅出顺序结构
🚀前言 本期是一篇关于顺序结构的题目的复盘,通过复盘基础知识,进而把基础知识学习牢固!通过例题而进行复习基础知识。 🚩目录 前言 1.字符三角形 分析: 知识点: 代码如下 2. 字母转换 题目分析: 知…...

尚无忧【无人共享空间 saas 系统源码】无人共享棋牌室系统源码共享自习室系统源码,共享茶室系统源码
可saas多开,非常方便,大大降低了上线成本 UNIAPPthinkphpmysql 独立开源! 1、定位功能:可定位附近是否有店 2、能通过关键字搜索现有的店铺 3、个性轮播图展示,系统公告消息提醒 4、个性化功能展示,智能…...

SQL Server 恢复软件
Datanumen SQL Server 软件主要特点 支持 Microsoft SQL Server 2005、2008、2008 R2、2012、2014、2016、2017、2019、2022 。 恢复表中的架构/结构和数据。 恢复所有数据类型,包括 ASCII 和 Unicode XML 数据类型。 恢复稀疏列。 恢复数据库表中已删除的记录…...

奇安信天擎 rptsvr 任意文件上传漏洞复现
0x01 产品简介 奇安信天擎是奇安信集团旗下一款致力于一体化终端安全解决方案的终端安全管理系统(简称“天擎”)产品。通过“体系化防御、数字化运营”方法,帮助政企客户准确识别、保护和监管终端,并确保这些终端在任何时候都能可信、安全、合规地访问数据和业务。天擎基于…...

Linux-nginx(安装配置nginx、配置反向代理、Nginx配置负载均衡、动静分离)
关于代理 正向代理: 客户明确知道自己访问的网站是什么 隐藏客户端的信息 目录 关于代理 一、Nginx的安装与配置 1、安装依赖 2、安装nginx (1)上传压缩包到目录 /usr/nginx里面 (2)解压文件 (3)…...

阿里云GPU服务器ECS实例规格详细说明
阿里云GPU服务器提供GPU加速计算能力,GPU卡支持A100、V100、T4、P4、P100、A10等,NVIDIA V100,GPU实例规格是什么意思?如搭载NVIDIA V100的ecs.gn6v-c8g1.2xlarge、A10卡ecs.gn7i-c32g1.8xlarge、T4卡ecs.gn6i-c4g1.xlarge、P4卡e…...

Kafka为什么在消息积压时不能直接通过消费者水平扩容来提升消费速度?
我们知道当消息生产者生产的速度快于消费者的消费速度时,会产生大量的消息积压,大多数人的想法是增加消费者的数量来提升消费速度,这个想法在RocketMQ中是可行的,但是在Kafka中不一定可行。为了更方便地分析问题,我们先…...

“揭秘Maven:如何成为大数据项目的管理能手?“
介绍:Maven是一个项目管理和构建自动化工具,广泛应用于Java项目中。具体来说:项目对象模型(POM):Maven通过一个名为POM的模型来描述项目信息,包括项目的坐标、依赖关系、插件目标等。这个模型通…...

基于BERT对中文邮件内容分类
用BERT做中文邮件内容分类 项目背景与意义项目思路数据集介绍环境配置数据加载与预处理自定义数据集模型训练加载BERT预训练模型开始训练 预测效果 项目背景与意义 本文是《用BERT做中文邮件内容分类》系列的第二篇,该系列项目持续更新中。系列的起源是《使用Paddl…...

【EFCore仓储模式】介绍一个EFCore的Repository实现
阅读本文你的收获 了解仓储模式及泛型仓储的优点学会封装泛型仓储的一般设计思路学习在ASP.NET Core WebAPI项目中使用EntityFrameworkCore.Data.Repository 本文中的案例是微软EntityFrameworkCore的一个仓储模式实现,这个仓储库不是我自己写的,而是使…...

oracle篇—19c新特性自动索引介绍
☘️博主介绍☘️: ✨又是一天没白过,我是奈斯,DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux,也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章,并且也会默默的点赞收藏加关注❣…...

稳定性——JE流程
1. RuntimeInit.commonInit() 上层应用都是由Zygote fork孵化出来的,分为system_server进程和普通应用进程进程创建之初会设置未捕获异常的处理器,当系统抛出未捕获的异常时候都会交给异常处理器RuntimeInit.java的commonInit方法设置UncaughtHandler …...
【控制篇 / 分流】(7.4) ❀ 03. 对国内和国际IP网段访问进行分流 ❀ FortiGate 防火墙
【简介】公司有两条宽带用来上网,一条电信,一条IPLS国际专线,由于IPLS仅有2M,且价格昂贵,领导要求,访问国内IP走电信,国际IP走IPLS,那么应该怎么做? 国内IP地址组 我们已…...

01-开始Rust之旅
上一篇:00-Rust前言 1. 下载Rust 官方推荐使用 rustup 下载 Rust,这是一个管理 Rust 版本和相关工具的命令行工具。下载时需要连接互联网。 这边提供了离线安装版本。本人学习的机器环境为: ubuntu x86_64,因此选用第②个工具链&a…...

华南理工大学数字信号处理实验实验一(薛y老师版本)matlab源码
一、实验目的 1、加深对离散信号频谱分析的理解; 2、分析不同加窗长度对信号频谱的影响; 3、理解频率分辨率的概念,并分析其对频谱的 影响; 4、窗长和补零对DFT的影响 实验源码: 第一题: % 定义离散信…...

一篇文章看懂云渲染,云渲染是什么?云渲染如何计费?云渲染怎么选择
云渲染是近年兴起的新行业,很多初学者对它不是很了解,云渲染是什么?为什么要选择云渲染?它是如何计费的又怎么选择?这篇文章我们就带大家了解下吧。 云渲染是什么 云渲染简单来说就是把本地的渲染工作迁移到云端进行的…...

C++进阶--哈希表模拟实现unordered_set和unordered_map
哈希表模拟实现unordered_set和unordered_map 一、定义哈希表的结点结构二、定义哈希表的迭代器三、定义哈希表的结构3.1 begin()和end()的实现3.2 默认成员函数的实现3.2.1 构造函数的实现3.2.2 拷贝构造函数的实现(深拷贝)3.2.3 赋值运算符重载函数的实…...

Elasticsearch各种高级文档操作
本文来记录下Elasticsearch各种文档操作 文章目录 初始化文档数据查询所有文档匹配查询文档关键字精确查询文档多关键字精确查询文档字段匹配查询文档指定查询字段查询文档过滤字段查询文档概述指定想要显示的字段示例指定不想要显示的字段示例 组合查询文档范围查询文档概述使…...

激光无人机打击系统——光束控制和指向系统
激光无人机(UAV)打击系统中的光束控制和指向系统通常包括以下几个关键组件和技术: 激光发射器:这是系统的核心,负责生成高能量的激光束。常用的激光类型包括固体激光器、化学激光器、光纤激光器等,选择取决…...

pycharm import torch
目录 1 安装 2 conda环境配置 3 测试 开始学习Pytorch! 1 安装 我的电脑 Windows 11 Python 3.11 Anaconda3-2023.09-0-Windows-x86_64.exe cuda_11.8.0_522.06_windows.exe pytorch (管理员命令行安装) pycharm-community-2023.3.2.exe 2 c…...

flask 与小程序 购物车删除和编辑库存功能
编辑 : 数量加减 价格汇总 数据清空 mina/pages/cart/index.wxml <!--index.wxml--> <view class"container"><view class"title-box" wx:if"{{ !list.length }}">购物车空空如也~</view>…...

蓝桥杯真题(Python)每日练Day3
题目 题目分析 为了找到满足条件的放置方法,可以带入总盘数为2和3的情景,用递归做法实现。 2. A中存在1 2两个盘,为了实现最少次数放入C且上小下大,先将1放入B,再将2放入C,最后将1放入C即可。同理当A中存在…...

结构体大揭秘:代码中的时尚之选(上)
目录 结构结构的声明结构成员的类型结构体变量的定义和初始化结构体成员的访问结构体传参 结构 结构是一些值的集合,这些值被称为成员变量。之前说过数组是相同类型元素的集合。结构的每个成员可以是不同类型的变量,当然也可以是相同类型的。 我们在生活…...