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

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》


我的个人博客:https://zhengnianli.github.io/

我的微信公众号:嵌入式大杂烩

我的CSDN博客:https://blog.csdn.net/zhengnianli


 上一篇
易错、经典问题:return不可返回指向栈内存的指针 易错、经典问题:return不可返回指向栈内存的指针
预备知识:内存的分类C/C++程序占用的内存分为两大类:静态存储区与动态存储区。其示意图如下所示: 数据保存在静态存储区与动态存储区的区别就是:静态存储区在编译-链接阶段已经确定了,程序运行过程中不会变化,只有当程序退出的时候,静态存储区
2019-09-06
下一篇 
C语言代码优化的一些经验及小技巧(四) C语言代码优化的一些经验及小技巧(四)
无限循环优先选用for(;;),而不是while(1)在C语言中,最常用的无限循环语句主要有两种:while(1)和for(;;)。从功能上讲, 这两种语句的效果完全一样。那么,我们究竟该选择哪一种呢? 其实,for(;;)语句运行速度要快
2019-08-30
  目录