前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RT-Thread的对象容器设计思想浅析

RT-Thread的对象容器设计思想浅析

作者头像
bigmagic
发布2020-05-27 22:49:06
1.3K0
发布2020-05-27 22:49:06
举报
文章被收录于专栏:嵌入式iot嵌入式iot嵌入式iot

1.本文概述

最近在学习RT-Thread操作系统的内核部分设计。RT-Thread的面向对象编程思想非常的巧妙,可以看我之前的写的文章。

RT-Thread面向对象编程思路浅析

而对象(rt_object)的管理又是一个可以深入理解的地方。简单的说,就是我们创建线程,或者创建邮箱,创建信号量等,最后都抽象成对象的管理。

看一下上面的图例。用文字表述就是,所有的线程、IPC、设备创建的时候,都会通过链表被挂载在对象容器中。

2.对象容器

结合上一章的图不难理解,对象容器就是一个二维的数组,对象的类型以及具体某个对象的链表。

在rt-thread中,对象容器的代码实现是一个静态的二维数组。

可以查看rt-thread\src\object.c的具体数组实现:

#define _OBJ_CONTAINER_LIST_INIT(c)     \
    {&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)}
static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] =
{
    /* initialize object container - thread */
    {RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
#ifdef RT_USING_SEMAPHORE
    /* initialize object container - semaphore */
    {RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
#endif
#ifdef RT_USING_MUTEX
    /* initialize object container - mutex */
    {RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
#endif
#ifdef RT_USING_EVENT
    /* initialize object container - event */
    {RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
#endif
#ifdef RT_USING_MAILBOX
    /* initialize object container - mailbox */
    {RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
#endif
#ifdef RT_USING_MESSAGEQUEUE
    /* initialize object container - message queue */
    {RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
#endif
#ifdef RT_USING_MEMHEAP
    /* initialize object container - memory heap */
    {RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
#endif
#ifdef RT_USING_MEMPOOL
    /* initialize object container - memory pool */
    {RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
#endif
#ifdef RT_USING_DEVICE
    /* initialize object container - device */
    {RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
#endif
    /* initialize object container - timer */
    {RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
#ifdef RT_USING_MODULE
    /* initialize object container - module */
    {RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
#endif
};

其中rt_object_information的定义

struct rt_object_information
{
    enum rt_object_class_type type;                     /**< object class type */
    rt_list_t                 object_list;              /**< object list */
    rt_size_t                 object_size;              /**< object size */
};

也就是对象容器的属性有大小,也有对象数据链表。当任意时刻,获取到rt_object_container[RT_Object_Info_Unknown]的地址,然后解析,即可得到当前系统中线程的信息、IPC的信息以及设备状态信息,这样去实现类似于PS命令就十分简单了。

事实上,rt-thread中的list_threadlist_sem等函数的具体实现也是基于这个对象容器获取到的。

3.对象容器的管理

基于RT-Thread的对象的思想,对象管理肯定有创建、脱离这样的操作。

具体看一下线程创建的实例。

当调用rt_thread_create函数去创建线程时,会调用下面函数去创建一个对象。

thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
                                                    name);

而这个申请对象函数的实现其实就是从对象容器中插入一个线程

information = rt_object_get_information(type);//得到对象容器的thread对象

接着初始化对应的线程对象,然后插入线程对象到容器中。

/* insert object into information object list */
rt_list_insert_after(&(information->object_list), &(object->list));

然后对象容器中就存在这个线程的链表了,通过查询链表获得具体的线程信息。

当线程delete的时候,也是调用这个函数,从而将链表从对象中脱离。

rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));

在rt-thread中,很多操作就是通过这种方式实现线程的创建和销毁的。

4.手动去解析对象容器

这确实是非常有意思的事情,通过一个地址,就可以获取系统的整个运行状态信息。

  extern struct rt_object_information rt_object_container[];
    rt_uint8_t * my_addr = (rt_uint8_t *)rt_object_container;
    struct rt_object_information * t32_rt_thread_container = (struct rt_object_information *)my_addr;
    struct rt_object_information * t32_rt_semaphore_container = t32_rt_thread_container + 1;
    struct rt_object_information * t32_rt_mutex_container = t32_rt_semaphore_container + 1;
    struct rt_object_information * t32_rt_event_container = t32_rt_mutex_container + 1;
    struct rt_object_information * t32_rt_mailbox_container = t32_rt_event_container + 1;
    struct rt_object_information * t32_rt_messagequeue_container = t32_rt_mailbox_container + 1;
    struct rt_object_information * t32_rt_memheap_container = t32_rt_messagequeue_container + 1;
    struct rt_object_information * t32_rt_device_container = t32_rt_memheap_container + 1;
    struct rt_object_information * t32_rt_timer_container = t32_rt_device_container + 1;
    struct rt_object_information * t32_rt_module_container = t32_rt_timer_container + 1;

通过导出对象容器二维数组的地址,获取各个类型对象的列表。

比如要想获取系统当前运行的线程相关的信息

    rt_list_t* thread_list;
    thread_list = t32_rt_thread_container->object_list.next;

    rt_thread_t rtt_thread;
    rtt_thread = (rt_thread_t)(thread_list - 1);
    
    while (1)
    {
        if(rtt_thread->stack_size < 20480)
        {
            rt_kprintf("rtt_thread->name is %s\n", rtt_thread->name);
            switch (rtt_thread->stat)
            {
            case RT_THREAD_INIT:
                rt_kprintf("RT_THREAD_INIT\n");
                break;
            case RT_THREAD_READY:
                rt_kprintf("RT_THREAD_READY\n");
                break;
            case RT_THREAD_SUSPEND:
                rt_kprintf("RT_THREAD_SUSPEND\n");
                break;
            case RT_THREAD_RUNNING:
                rt_kprintf("RT_THREAD_RUNNING\n");
                break;
            case RT_THREAD_CLOSE:
                rt_kprintf("RT_THREAD_CLOSE\n");
                break;
            default:
                break;
            }
            // rt_kprintf("rtt_thread->list is %p\n", rtt_thread->list);
            // rt_kprintf("rtt_thread->type is %p\n", rtt_thread->type);
            // rt_kprintf("rtt_thread->stack_size is %p\n", rtt_thread->stack_size);
            // rt_kprintf("rtt_thread->number_mask is %p\n", rtt_thread->number_mask);
        }
        else
        {
            break;
        }
        
        thread_list = thread_list->next;
        rtt_thread = (rt_thread_t)(thread_list - 1);
    }

这样就可以解析到当前系统中对象相关的信息了。其中比较重要的一个理解就是,线程链表其实指向的就是线程的结构体的首地址。这样解析起来就非常的容易了。

5.总结

通过对象容器,可以获取系统信息,因为rt-thread的一切皆对象的设计思想,这种设计有很多好处。对象的管理需要相应的容器进行管理,这部分确实值得好好理解与学习。以后写嵌入式代码也需要有架构,有设计,有管理器,这样设计出来的代码才更加的可靠以及易于扩展。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式IoT 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.本文概述
  • 2.对象容器
  • 3.对象容器的管理
  • 4.手动去解析对象容器
  • 5.总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档