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中有那么多种内核对象,它是怎么管理这些内核对象呢?其使用对象容器来管理这些对象。这个对象容器给每一类内核对象分配一个链表,每当创建一个对象实体,这个对象实体就被链接到对应的链表上,如:
这个对象容器对应到代码中是一个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)}
初始化对象列表节点头里面的next
和prev
两个节点指针分别指向自身,如:
若创建两个线程对象,则对象容器里变为:
End:以上就是本次的笔记分享,如有错误,欢迎之处!
参考资料:
1、《RT-Thread编程指南》
2、[野火]《RT-Thread 内核实现与应用开发实战—基于STM32》
我的个人博客:https://zhengnianli.github.io/
我的微信公众号:嵌入式大杂烩