查看原文
其他

【RT-Thread笔记】内核对象模型

ZhengNL 嵌入式大杂烩 2021-01-31

点击上方「嵌入式大杂烩」,选择「置顶公众号」第一时间查看编程笔记!

RT-Thread中的对象有哪些?

RT-Thread包括了很多不同类型的对象,如线程,信号量,互斥量等。在代码中,这些对象被汇总到一个枚举中(在rtdef.h中):

左右滑动查看全部代码>>>

enum rt_object_class_type
{
    RT_Object_Class_Null   = 0,          /**< 这个对象是未使用 */
    RT_Object_Class_Thread,              /**< 对象是线程 */
    RT_Object_Class_Semaphore,           /**< 对象是信号量 */
    RT_Object_Class_Mutex,               /**< 对象是互斥量 */
    RT_Object_Class_Event,               /**< 对象是事件 */
    RT_Object_Class_MailBox,             /**< 对象是邮箱 */
    RT_Object_Class_MessageQueue,        /**< 对象是消息队列 */
    RT_Object_Class_MemHeap,             /**< 对象是内存堆 */
    RT_Object_Class_MemPool,             /**< 对象是内存池 */
    RT_Object_Class_Device,              /**< 对象是设备 */
    RT_Object_Class_Timer,               /**< 对象是定时器 */
    RT_Object_Class_Module,              /**< 对象是模块 */
    RT_Object_Class_Unknown,             /**< 对象未知 */
    RT_Object_Class_Static = 0x80        /**< 对象是静态对象 */
};

在RT-Thread中,为了能很好的管理这些对象,专门定义了一个对象结构体(对象控制块),如下(在rtdef.h中):

左右滑动查看全部代码>>>

struct rt_object
{

    char       name[RT_NAME_MAX];       /**< 内核对象的名字 */
    rt_uint8_t type;                    /**< 内核对象的类型 */
    rt_uint8_t flag;                    /**< 内核对象的状态 */

#ifdef RT_USING_MODULE
    void      *module_id;               /**< 模块ID */
#endif
    rt_list_t  list;                    /**< 内核对象的列表节点 */
};
typedef struct rt_object *rt_object_t;  /**< 内核对象数据类型重定义 */

这个对象结构体包含的信息都是各类对象的公共部分。每类对象都有创建一个对应的结构体,如:

定时器对象

线程对象

有点不明白的是,线程对象结构体怎么直接把rt_object里的内容全搬过来了,而不是像定时器对象结构体那样定义一个rt_object类型的成员以达到继承的目的。

RT-Thread代码的层次感很强,让我们学习起来很有条理,比如信号量、互斥量、事件、邮箱、消息队列这几类对象具有共性,都是用于线程间的同步及通信(即IPC对象)。然后,RT-Thread又把这些公共的信息给抽取出来成一个新的结构体。如:

信号量对象:

IPC:Inter-ProcessCommunication,进程间通信。在RT-Thread实时操作系统中,IPC对象的作用是进行线程间同步与通信。

C语言虽是一门面向过程的语言,但此处,我们知道在C中也可以使用面向对象的思想来设计的程序。以上这些内核对象继承关系可以用下面这张图清楚地表示:


什么是静态对象、动态对象?

RT-Thread内核采用面向对象的设计思想进行设计。其内核对象分为两类:静态内核对象动态内核对象

静态内核对象使用的内存空间是编译时决定的,且运行过程中是不会变化的,只有当程序退出的时候这些内存空间才会被系统回收。

动态内核对象使用的内存空间是动态分配的,即在程序运行过程中动态分配的。动态对象依赖于堆管理器,运行时申请RAM空间,当对象被删除后,占用的RAM空间被释放。关于C语言的内存的知识可查看往期笔记:【C语言笔记】内存总结

关于对象的创建与删除的接口在源文件object.c中,object.c有如下接口:

静态对象的创建与删除

静态对象的创建(初始化)接口:

左右滑动查看全部代码>>>

void rt_object_init(struct rt_object         *object,  /* 对象指针 */
                    enum rt_object_class_type type,    /* 对象类型 */
                    const char               *name)
;   /* 对象名字 */

静态对象的删除(脱离)接口:

void rt_object_detach(rt_object_t object);

该接口的作用是把静态对象从内核管理器中脱离出来。静态对象脱离后,对象占用的内存并不会被释放。

动态对象的创建与删除

动态对象的创建(分配)接口:

左右滑动查看全部代码>>>

rt_object_t rt_object_allocate(enum rt_object_class_type type,  /* 对象类型 */
                               const char *name);               /* 对象名字 */

返回值RT_NULL则表示分配失败,否则,分配成功的对象句柄。

动态对象的删除接口:

void rt_object_delete(rt_object_t object);

当调用以上接口时,首先从对象容器链表中脱离对象,然后释放对象所占用的内存。

RT-Thread如何管理内核对象?

RT-Thread中有那么多种内核对象,它是怎么管理这些内核对象呢?其使用对象容器来管理这些对象。这个对象容器给每一类内核对象分配一个链表,每当创建一个对象实体,这个对象实体就被链接到对应的链表上,如:

这个对象容器对应到代码中是一个struct rt_object_information类型的结构体数组rt_object_container[RT_Object_Info_Unknown]。其中RT_Object_Info_Unknown的值为对象类型的种数。RT-Thread是一个可裁剪的系统,可以通过相应宏打开/关闭对象模块,所以这个值是根据最终对象类型种类确定的。

C语言知识:如果枚举类型的成员值没有具体指定,那么后一个值是在前一个成员值的基础上加1。

struct rt_object_information的内容如下:

其中,rt_list_t是一个双链表结点结构体,该结构体如下:

结构体数组(对象容器)rt_object_container中的对象链表初始化为:

其中,_OBJ_CONTAINER_LIST_INIT是一个宏,该宏内容如下:

左右滑动查看全部代码>>>

#define _OBJ_CONTAINER_LIST_INIT(c)     \
    {&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}

初始化对象列表节点头里面的nextprev两个节点指针分别指向自身,如:

若创建两个线程对象,则对象容器里变为:


End:以上就是本次的笔记分享,如有错误,欢迎之处!如果这篇笔记对你有帮助的话,欢迎收藏、转发、在看~

参考资料:

1、《RT-Thread编程指南》
2、[野火]RT-Thread 内核实现与应用开发实战—基于STM32》


猜你喜欢:

【RT-Thread笔记】内核基础

【RT-Thread笔记】裸机系统与多线程系统

【RT-Thread笔记】关于RT-Thread的启动问题

替代串口打印,另一种打印调试的方法



我的个人博客:

https://zhengnianli.github.io


查看往期笔记:

聊天界面输入m获取往期笔记目录


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存