【linux kernel】 一文总结linux内核中的kobject、kset和ktype

文章目录

        • 一、kobject、kset、ktype
          • (1-1)kobject
          • (1-2)ktype
          • (1-3)kset
        • 二、kobject操作API
          • (2-1)kobject_init()
          • (2-2)kobject_add()
          • (2-3)kobject_rename()
          • (2-4)kobject_name()
          • (2-5)kobject_get()
          • (2-6)kobject_put()
          • (2-7)kobject_del()
          • (2-8)kobject_move()
          • (2-9)kobject_uevent
          • (2-10)kobject_uevent_env
        • 三、引用计数
        • 四、创建简单的kobject
        • 五、移除kobject
        • 六、kset提供的功能

一、kobject、kset、ktype

kobject是内核中表示对象的基本结构,kset是用于组织和管理 kobject 的集合,而 ktype 是用于定义 kobject 的类型。通过使用这三个概念,可以实现内核对象的管理、组织和操作,kobjectksetktype是内核中核心基础结构,绚丽多彩的内核世界在这些基础结构上逐一构建。

(1-1)kobject

kobjectstruct kobject类型的对象。kobjects有一个名称name和一个引用计数。kobject还有一个父指针(允许对象被安排到层次结构中),一个特定的类型ktype,一个特定的对象集合kset,以及一个是否在sysfs虚拟文件系统中的状态表示。struct kobject是linux内核中的数据结构,用于表示内核对象(Kernel Object)。它是Linux设备模型的核心之一,用于表示内核中的各种实体,如设备、驱动程序、总线、类别等。

struct kobject提供了一种统一的方式来管理内核中的对象。它允许内核开发人员创建具有层次结构的对象树,通过父子关系链表关系连接不同的对象。通过与sysfs文件系统的集成,可以为每个内核对象创建相应的sysfs文件,使用户空间能够查看和修改对象的属性。

struct kobject还提供了引用计数的机制,确保在对象不再被使用时能够正确释放相关资源。引用计数允许多个实体引用同一个内核对象,并在所有引用都被释放时自动销毁对象。kobject通常被嵌入到其他结构中。

🔺注意:任何结构中只能嵌入一个kobject

struct kobject定义如下:

struct kobject {
	const char		*name;
	struct list_head	entry;
	struct kobject		*parent;
	struct kset		*kset;
	struct kobj_type	*ktype;
	struct 	*sd;
	struct kref		kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
	struct delayed_work	release;
#endif
	unsigned int state_initialized:1;
	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;
};
  • name:内核对象的名称
  • entry:用于将内核对象添加到父对象的子对象列表中。
  • parent:指向父对象的指针,用于构建对象之间的层次关系。
  • kset:指向所属的kset(kobject集合)的指针,用于进行对象管理。
  • ktype:指向对象类型的指针,描述了对象的行为和属性。
  • sd:指向sysfs目录实体(sysfs_dirent)的指针,用于与sysfs文件系统进行交互。
  • kref:用于实现引用计数,确保在对象不再需要时能够正确释放资源。
(1-2)ktype

ktype是嵌入在kobject中的对象类型,用于描述struct kobject的类型和行为。每个kobject结构都需要对应的ktype,因为ktype用于控制创建和销毁kobjec时发生的事情。

struct kobj_type {
	void (*release)(struct kobject *kobj);
	const struct sysfs_ops *sysfs_ops;
	struct attribute **default_attrs;
	const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
	const void *(*namespace)(struct kobject *kobj);
};
  • release:指向释放对象资源的函数指针。当对象的引用计数变为零时,将调用此函数来释放对象相关的资源。
  • sysfs_ops:指向struct sysfs_ops的指针,用于定义sysfs文件系统操作的回调函数。通过这些回调函数,可以自定义sysfs文件的读取、写入、属性创建等操作。
  • default_attrs:指向struct attribute指针数组的指针,表示对象的默认属性。这些属性将在对象的sysfs目录中显示,并允许用户空间访问和修改。
  • child_ns_type:指向函数的指针,用于获取对象的子命名空间类型。如果对象具有子对象,并且这些子对象在命名空间上有不同的要求,可以通过此函数提供相应的命名空间类型操作。
  • namespace:指向函数的指针,用于获取对象的命名空间标识。命名空间标识是一个不透明的指针,用于标识对象所属的命名空间。

struct kobj_type用于描述struct kobject的类型和行为,为每个struct kobject实例提供相关的操作和属性定义。通过自定义struct kobj_type,可以定制不同类型的内核对象,并指定相应的release函数、属性、命名空间等。

在使用struct kobject时,通常会创建一个自定义的struct kobj_type实例,并将其与struct kobject关联。这样可以为每个对象提供独立的类型和行为,并在必要时通过回调函数和属性操作与用户空间进行交互。

每个kobject都必须有一个release()方法,并且该kobject必须持久化存在(保持一致的状态),直到release()被调用。

(1-3)kset

kset是一组kobject。这些kobject可以是相同的ktype,也可以属于不同的ktype。kset是kobject集合的基本容器类型。kset中也包含了一个自己的kobject,但是可以忽略实现细节,因为kset核心代码会自动处理这个kobject。kset如下定义:

struct kset {
    //这个kset的所有kobject的列表
	struct list_head list; 
    //用于遍历kobject的锁
	spinlock_t list_lock;
     //放在kset中的kobject
	struct kobject kobj;
    //kset的uevent操作集
	const struct kset_uevent_ops *uevent_ops; 
};

从根文件系统角度来看,当看到一个包含其他目录的sysfs目录时,通常每个目录都对应同一个kset中的一个kobject。

总而言之,struct kset用于表示内核对象的集合,它是一种特殊的struct kobject,用于将相关的内核对象组织成逻辑上的集合。通过struct kset,可以将一组具有相似特性或属性的内核对象归类并进行管理。

struct kset对象通常作为父对象,包含一组子对象,这些子对象可以是不同类型的内核对象,但它们在逻辑上具有某种相关性。例如,设备驱动程序可以创建一个struct kset对象,作为设备驱动程序的集合,每个具体的设备驱动程序都是其中的一个子对象。

struct kset提供了一些常用的操作和功能,如添加和删除子对象、遍历子对象等。通过对struct kset对象进行操作,可以很方便地管理和访问集合中的内核对象。

二、kobject操作API

kobject的接口位于/include/linux/kobject.h中,本小节总结常用的kobject操作API。

(2-1)kobject_init()
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
  • kobj:指向要初始化的内核对象的指针。
  • ktype:指向描述该内核对象类型的kobj_type结构体的指针。

ktype是创建kobject所必需的,因为每个kobject都必须有一个相关联的kobj_type。调用kobject_init()后,要向sysfs注册kobject,必须调用函数kobject_add()

(2-2)kobject_add()
int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);
  • kobj:指向要添加的内核对象的指针。
  • parent:指向父级内核对象的指针。新创建的内核对象将成为父级对象的子对象。
  • fmt:一个格式化字符串,用于指定要添加的内核对象的名称。

kobject_add()将正确地设置kobject的父对象和kobject的名称。如果kobject要与特定的kset相关联,则必须在调用kobject_add()之前分配kobj->kset。如果kset与kobject相关联,那么kobject的父对象可以在调用kobject_add()时设置为NULL,然后kobject的父对象将是kset本身。

由于kobject的名称是在添加到内核时设置的,因此不应该直接操作kobject的名称,如果必须修改kobject的名称,则调用kobject_rename():

一旦通过kobject_add()注册了kobject,就不能直接使用kfree()释放它,唯一安全的方法是使用kobject_put()完成。最好总是在kobject_init()之后使用kobject_put(),以避免出现错误。

(2-3)kobject_rename()
int kobject_rename(struct kobject *kobj, const char *new_name);

注意:kobject_rename()不执行任何锁操作,也不知道什么名称是有效的,因此调用者必须提供自己的健全检查和序列化。

(2-4)kobject_name()
const char *kobject_name(const struct kobject * kobj);

有一个helper函数可以同时初始化和将kobject添加到内核中,它的名字叫kobject_init_and_add():

int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,struct kobject *parent, const char *fmt, ...);
  • kobj:指向要初始化和添加的内核对象的指针。
  • ktype:指向描述该内核对象类型的kobj_type结构体的指针。
  • parent:指向父级内核对象的指针。新创建的内核对象将成为父级对象的子对象。
  • fmt:一个格式化字符串,用于指定新创建的内核对象的名称。此字符串可以包含格式化占位符,后面跟着对应的参数,类似于printf()函数的用法。

参数与上面描述的kobject_init()和kobject_add()函数相同。

(2-5)kobject_get()

kobject_get()函数用于增加给定 kobject 的引用计数:

struct kobject *kobject_get(struct kobject *kobj);
  • kobj:要增加引用计数的 kobject 的指针。

当某段代码需要继续使用 kobject 时,可以通过调用 kobject_get() 来增加其引用计数,从而防止其在其他地方被释放。通常,每个 kobject_get() 都应该有对应的 kobject_put() 来减少引用计数,以确保在不再需要时能够正确地释放 kobject。

(2-6)kobject_put()

kobject_put() 函数用于减少给定kobject的引用计数,并在引用计数减为零时释放相应的内存空间:

void kobject_put(struct kobject *kobj);
  • kobj:要减少引用计数的 kobject 的指针。

使用kobject_put()函数可以减少kobject的引用计数,当引用计数减为零时,表示没有代码再需要该kobject,并且可以安全地释放其占用的内存。通常每个 kobject_get()都应该有对应的 kobject_put() 来减少引用计数,以确保在不再需要时能够正确地释放 kobject。

(2-7)kobject_del()

kobject_del() 函数用于从内核对象层次结构中注销给定的 kobject:

void kobject_del(struct kobject *kobj);
  • kobj:要注销的 kobject 的指针。

调用kobject_del()函数将从内核对象层次结构中移除指定的kobject,这将使得 kobject 不再可见,但不会释放与之相关的内存,且其引用计数仍保持不变。通常,这个函数用于在不允许睡眠的情况下销毁对象,以确保在后续能够安全地完成对象的清理工作。要完全清理与 kobject 相关的内存,还需要在适当的时候调用 kobject_put()

(2-8)kobject_move()

kobject_move() 函数用于将一个 kobject 移动到另一个父对象下:

int kobject_move(struct kobject *kobj, struct kobject *new_parent)
  • kobj:要移动的 kobject 的指针。

  • new_parent:新的父对象的指针。

调用kobject_move()函数会将指定的 kobject 移动到另一个父对象下,这可以用于重新组织内核对象层次结构中的对象。移动后,kobject 将成为新父对象的子对象,并从原父对象的子对象列表中删除。

(2-9)kobject_uevent
int kobject_uevent(struct kobject *kobj, enum kobject_action action);

kobject_uevent()函数用于向用户空间发送一个与指定kobject对象关联的uevent事件。

  • kobj:指向要发送uevent事件的kobject对象的指针。
  • action:指定要发送的uevent事件的动作类型,通常是一个枚举类型。

成功时返回0,失败时返回负值。

使用kobject_uevent()函数,内核可以在发生特定事件时向用户空间发送通知,用户空间的程序可以监听这些事件并执行相应的操作。例如,在设备插入或移除时,内核可以调用kobject_uevent()函数发送相应的uevent事件,以通知用户空间发生了相关的变化。

请注意,kobject_uevent()函数只是将uevent事件添加到内核中的uevent队列中,实际的uevent处理是由对应的守护进程来完成的,它会从内核的uevent队列中获取事件并执行相应的操作。

enum kobject_action定义如下:

enum kobject_action {
	KOBJ_ADD,		//对象添加。表示向系统中添加了一个新的kobject对象。
	KOBJ_REMOVE,	//对象移除。表示从系统中移除了一个kobject对象。
	KOBJ_CHANGE,	//对象修改。表示kobject对象的属性或状态发生了变化。
	KOBJ_MOVE,		//对象移动。表示kobject对象被移动到了另一个位置。
	KOBJ_ONLINE,	//对象上线。表示kobject对象已经准备好在线工作。
	KOBJ_OFFLINE,	//对象离线。表示kobject对象已经离线,不再处于工作状态。
	KOBJ_MAX		//动作类型的最大值,用于边界检查。
};

这里给出了枚举类型kobject_action的定义,它包含了一组常见的kobject动作类型:

  • KOBJ_ADD:对象添加。表示向系统中添加了一个新的kobject对象。
  • KOBJ_REMOVE:对象移除。表示从系统中移除了一个kobject对象。
  • KOBJ_CHANGE:对象修改。表示kobject对象的属性或状态发生了变化。
  • KOBJ_MOVE:对象移动。表示kobject对象被移动到了另一个位置。
  • KOBJ_ONLINE:对象上线。表示kobject对象已经准备好在线工作。
  • KOBJ_OFFLINE:对象离线。表示kobject对象已经离线,不再处于工作状态。
  • KOBJ_MAX:动作类型的最大值,用于边界检查。

这些动作类型用于指示kobject_uevent()函数要发送的uevent事件的类型。当内核调用kobject_uevent()函数时,它会指定一个动作类型,告知用户空间发生了哪种类型的事件。用户空间的程序可以根据收到的uevent事件类型来执行相应的操作。

(2-10)kobject_uevent_env
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[])

kobject_uevent_env()函数与kobject_uevent()函数类似,用于向用户空间发送一个与指定kobject对象关联的uevent事件,但kobject_uevent_env允许在发送uevent事件时传递额外的环境变量。kobject_uevent()本质上也是调用kobject_uevent_env()实现,只是envp_ext位NULL。

  • kobj:指向要发送uevent事件的kobject对象的指针。
  • action:指定要发送的uevent事件的动作类型,通常是一个枚举类型。
  • envp_ext[]:一个字符串数组,包含要传递给用户空间的额外环境变量。数组中的每个元素都是一个以key=value格式表示的字符串,用于指定一个环境变量的键值对。

使用kobject_uevent_env()函数,内核可以在发生特定事件时向用户空间发送通知,并传递额外的环境变量信息。用户空间的程序可以监听这些事件并执行相应的操作,并根据收到的环境变量信息来进行进一步处理。

三、引用计数

kobject的关键功能之一是充当嵌入它的对象的引用计数器,只要对对象的引用存在,该对象(和支持它的代码)也必须继续存在。用于操作kobject引用计数的底层函数有:

struct kobject *kobject_get(struct kobject *kobj);
void kobject_put(struct kobject *kobj);

成功调用kobject_get()将增加kobject的引用计数器并返回指向该kobject的指针。当一个引用被释放时,对kobject_put()的调用将减少引用计数,并可能释放该对象。

注意,kobject_init()将引用计数设置为1,因此设置kobject的代码最终需要执行kobject_put()来释放该引用。

因为kobject是动态的,所以它们不能被静态地声明或在堆栈上声明,而是总是动态地分配。内核的未来版本将包含对静态创建的kobject的运行时检查,并将警告开发人员这种不当使用。

四、创建简单的kobject

有时候,我没仅仅想在在sysfs层次结构中创建一个简单的目录,而不必与复杂的kset、show和store函数以及其他细节纠缠在一起。则可以使用下列API创建这样的一个条目:

struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
  • name:指定新创建的内核对象的名称。
  • parent:指向父级内核对象的指针。新创建的内核对象将成为父级对象的子对象。

这个函数将创建一个kobject,并将它放在sysfs中指定的父kobject下面的位置。要创建与这个kobject相关的简单属性,需使用:

int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);

或者

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);

注意:这里使用的两种属性类型,以及使用kobject_create_and_add()创建的kobject,都可以是kobj_attribute类型,因此不需要创建特殊的自定义属性。

五、移除kobject

如果一个kobject成功注册到kobject核心后,当代码完成对其的使用时,必须对其进行清理,这时候需要调用kobject_put()。通过这样做,kobject核心将自动清理该kobject分配的所有内存。如果已为对象发送了KOBJ_ADD uevent,则将发送相应的KOBJ_REMOVE uevent,并且其他 sysfs 管理都将得到合适的处理。

如果我没需要对kobject进行两阶段删除(例如,当我们需要销毁对象时不能睡眠),那么可以调用kobject_del()将从sysfs注销kobject,这使得 kobject “不可见”,但它没有被清理,这时候对象的引用计数仍然相同,在后续调用kobject_put()来完成与kobject相关联的内存清理操作。

kobject_del() 可用于断开对父对象的引用,如果构造了循环引用。在某些情况下,父对象引用子对象是有效的,必须使用显式调用kobject_del()来中断循环引用,以便调用释放函数。

六、kset提供的功能

一个kset提供以下三个功能:

(1)kset就像一个装东西的袋子,里面装着一组物体。内核可以使用kset来跟踪“所有块设备”或“所有PCI设备驱动程序”。

(2)kset也是sysfs中的一个子目录,其中可以显示与kset相关联的kobject,每个kset都包含一个kobject,它可以被设置为其他kobject的父对象;sysfs层次结构的顶级目录就是这样构造的。

(3)kset可以支持kobject的"热插拔",并影响uevent事件如何报告给用户空间。

在面向对象的术语中,“kset”是顶级容器类;kset包含它们自己的kobject,但是kobject是由kset代码管理的,不应该由用户直接操作。

kset将其子节点保存在标准的内核链表中,kobject通过kset字段指向包含它们的kset。在几乎所有的情况下,属于kset的kobject都在它们的父对象中包含kset(或者严格地说是内嵌的kobject)。

由于kset中包含一个kobject,所以始终应该动态创建kset,而不是静态或在堆栈上声明它。

创建一个新的kset,代码如下:

struct kset *kset_create_and_add(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj);

当使用完kset之后,需要调用:

void kset_unregister(struct kset *k);

去销毁它。该函数将从sysfs中删除kset并减少其引用计数,当引用计数减为零时,kset将被释放。因为这时候对kset的其他引用可能仍然存在,所以释放操作可能发生在kset_unregister()返回之后。

如果kset希望控制与它关联的kobject的uevent的ops,它可以使用结构体kset_uevent_ops来处理,该结构定义如下:

struct kset_uevent_ops {
        int (* const filter)(struct kset *kset, struct kobject *kobj);
        const char *(* const name)(struct kset *kset, struct kobject *kobj);
        int (* const uevent)(struct kset *kset, struct kobject *kobj,
                      struct kobj_uevent_env *env);
};
  • filter:用于过滤要发送uevent的struct kobject对象。如果返回值为非零,则表示该对象的uevent将被发送;如果返回值为零,则表示该对象的uevent将被忽略。
  • name:用于获取要发送uevent的struct kobject对象的名称,返回的字符串将作为uevent中的"NAME"字段。
  • uevent:用于发送uevent的回调函数。它将会在struct kobject对象的uevent触发时被调用,并接收struct kobject对象、struct kobj_uevent_env环境变量作为参数。

通过定义struct kset_uevent_ops 结构体,并将其赋值给struct kset对象的uevent_ops成员,可以自定义struct kset对象的uevent操作行为。当相关的内核对象发生与uevent相关的事件时,内核将调用struct kset_uevent_ops 中定义的函数来处理和发送uevent。

使用struct kset_uevent_ops,可以灵活地定义struct kset对象的uevent行为,例如过滤要发送的uevent对象、指定uevent中的名称字段、处理和发送uevent等。这能够在内核对象发生变化时,根据需要触发自定义的操作和通知。

参考链接:

https://www.kernel.org/doc/html/latest/core-api/kobject.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/560494.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营DAY28|C++回溯算法Part.4|93.复原IP地址、78.子集、90.子集II

文章目录 93.复原IP地址思路确定非法的范围树形结构 伪代码 78.子集思路伪代码实现CPP代码 90.子集II思路CPP代码用used去重的办法用set去重的版本不使用used数组、set的版本 93.复原IP地址 力扣题目链接 文章讲解:93.复原IP地址 视频讲解:回溯算法如何分…

curlftpfs和fusermount

curlftpfs 是一种 Linux 系统下用来将 FTP 服务器挂载为文件系统的工具,这意味着可以通过本地目录来访问和操作 FTP 服务器上的文件。 挂载FTP服务器到本地系统 为了挂载FTP服务器到本地系统中,使用curlftpfs工具,可以按照以下格式书写命令…

如何通过MSTSC连接Ubuntu的远程桌面?

正文共:666 字 12 图,预估阅读时间:1 分钟 前面我们介绍了如何通过VNC连接Ubuntu 18.04的远程桌面(Ubuntu 18.04开启远程桌面连接),非常简单。但是有小伙伴咨询如何使用微软的远程桌面连接MSTSC&#xff08…

黑灰产行业简介

参考:2021年黑灰产行业研究及趋势洞察报告 1. 有哪些场景面临大量黑灰产攻击? 1.营销活动场景 -- 该场景最为猖獗 1. 抹机及接码注册:黑灰产会使用抹机工具修改设备参数伪装成一台新设备,再配合联系卡商进行手机号接码&#xf…

项目7-音乐播放器3(删除模块+播放音乐模块设计)

1.播放音乐模块设计 1.1 请求响应设计 请求: { get, /music/get?pathxxx.mp3 } 响应: { 音乐数据本身的字节信息 } 1.2 后端代码 1. Files.readAllBytes(String path) : 读取文件中的所有字节,读入内存 &#xff…

java/C#语言开发的医疗信息系统10套源码

java/C#语言开发的医疗信息系统10套源码 云HIS系统源码,云LIS系统源码,PEIS体检系统,手麻系统 源 码,PACS系统源码,微源预约挂号源码,医院绩效考核源码,3D智能导诊系统源码,ADR药物…

UE5(基础动作)多人游戏制作蹲伏

1.创建输入操作,IA_Crouch 在输入映射中添加 IA_Crouch,在触发器中创建两个索引,已按下已松开来创建蹲伏输入。 蹲伏操作必须要勾选角色-角色移动-crouch勾选可蹲伏否则你的人物无法真正蹲下。 为蹲伏创建函数,创建布尔来判断是否蹲伏。 通过…

链表经典算法OJ题目

1.单链表相关经典算OJ题目1:移除链表元素 思路一 直接在原链表里删除val元素,然后让val前一个结点和后一个节点连接起来。 这时我们就需要3个指针来遍历链表: pcur —— 判断节点的val值是否于给定删除的val值相等 prev ——保存pcur的前…

LCR 023. 相交链表

给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后&#xf…

大话设计模式-装饰器模式

大话设计模式书中,作者举了一个穿衣服的例子来为我们引入装饰器模式。 概念 定义 装饰模式在书中的定义是:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。 这句话直接去理解可能会有点抽象&#…

javase__进阶 day13stream流和方法引用

1.不可变集合 1.1 什么是不可变集合 ​ 是一个长度不可变,内容也无法修改的集合 1.2 使用场景 ​ 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。 ​ 当集合对象被不可信的库调用时,不可变形式是安全的。 简单…

java:Java中的抽象类

什么是抽象类: 我们知道,类用来模拟现实的事物,一个类模拟一类事物,某个类的一个实例化对象可以模拟某个属于该类的具体事物。类中描绘了该类所有对象的共同的特性,当一个类中给出的信息足够全面时候,我们就…

如何从零开始创建React应用:简易指南

🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…

【大模型应用极简开发入门(1)】LLM概述:LLM在AI中所处位置、NLP技术的演变、Transformer与GPT、以及GPT模型文本生成逻辑

文章目录 一. AI中大语言模型的位置与技术发展1. 从AI到Transformer2. NLP:自然语言处理3. LLM大型语言模型:NLP的一种特定技术3.1. LLM定义3.2. LLM的技术发展3.2.1. n-gram模型3.2.2. RNN与LSTM 二. Transformer在LLM中脱颖而出1. Transformer架构能力…

【Linux】详解进程通信中信号量的本质同步和互斥的概念临界资源和临界区的概念

一、同步和互斥的概念 1.1、同步 访问资源在安全的前提下,具有一定的顺序性,就叫做同步。在多道程序系统中,由于资源有限,进程或线程之间可能产生冲突。同步机制就是为了解决这些冲突,保证进程或线程之间能够按照既定…

sketchup创建3D打印机的模型

查了一下,这玩意有几个版本,其中一个sketchup free是免费的,到官网上看看 下载 SketchUp | 免费试用 3D 建模软件 | SketchUp 是个在线网页版,然后可以再这个网站上注册一个账号 弄个邮箱试试看 创建好进入后,里面就…

解锁多智能体路径规划新境界:结合启发式搜索提升ML本地策略

引言:多智能体路径寻找(MAPF)问题的重要性与挑战 在现代自动化和机器人技术迅速发展的背景下,多智能体路径寻找(Multi-agent path finding,简称MAPF)问题的研究变得日益重要。MAPF问题涉及为一…

《QT实用小工具·二十七》各种炫酷的样式表

1、概述 源码放在文章末尾 该项目实现了各种炫酷的样式表,如单选、多选、按钮、日历、表格、下拉框、滚轮等,下面是项目demo演示: 项目部分代码如下: #include "frmmain.h" #include "ui_frmmain.h" #inc…

【C++】飞机大战项目记录

源代码与图片参考自《你好编程》的飞机大战项目,这里不进行展示。 本项目是仅供学习使用的项目 飞机大战项目记录 飞机大战设计报告1 项目框架分析1.1 敌机设计:1.2 玩家飞机控制:1.3 子弹发射:1.4 游戏界面与互动:1.5…

高精度算法(2)

前言 延续上次所讲的内容再对乘法和除法进行说明,希望有所帮助 注意这里的乘除法都是针对于整数如果要是涉及到小数,我们得使用二分法 通过二分同样可以解决小数精度问题 高精度乘法 思路 我们只能用字符串来读取一个很大很大的数,所以…