干货 | 扒一扒RT-Thread内核对象管理器设计思路

RT-Tread内核架构

RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统,基本属性之一是支持多任务,允许多个任务同时运行并不意味着处理器在同一时刻真地执行了多个任务。其内核架构如下图所示:

RT-Thread 内核及底层结构

对于各部分的功能,这里不做展开描述。RT-Tread内核吸引我的方面:

  • 代码优雅、可读性非常高
  • 体积小巧、代码类Linux风格,可裁剪
  • 社区活跃,国人自主开发,用户越来越多
  • 优秀的设计,对于面向对象设计思想可以说是非常优秀的实践
  • 主要定位于物联网应用,各种组件丰富,融合的也很好
  • ........

所以如果是RTOS应用或者开发从业者,面对这么优秀且比较容易深入学习的内核,如果不去好好读读,实在有点可惜。要去体会RT-Thread对象设计思想,从其对内核对象object的管理入手,不失为一个非常好的切入点。

什么是RT-Thread内核对象管理?

RT-Thread 采用内核对象管理系统来访问 / 管理所有内核对象,内核对象包含了内核中绝大部分设施,这些内核对象既可以是静态分配的静态对象,也可以是从系统内存堆中分配的动态对象。通过这种内核对象的设计方式,RT-Thread 做到了不依赖于具体的内存分配方式,系统的灵活性得到极大的提高。

RT-Thread 内核对象包括:线程,信号量,互斥量,事件,邮箱,消息队列和定时器,内存池,设备驱动等。对象容器中包含了每类内核对象的信息,包括对象类型,大小等。对象容器给每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上,如图 RT-Thread 的内核对象容器及链表如下图所示:

RT-Thread 的内核对象容器及链表

参考自:https://www.rt-thread.org/document/site/programming-manual/basic/basic/#_7

这个集中管理的内核对象容器在内存的开销方面代价很小,但却具有高度的灵活性,从设计的角度看其代码也非常利于扩展,增加新的内核对象类别,以及对于相应的内核对象功能的裁剪适配。

内核对象主要干什么?

RT-Thread内核对象子系统其主体实现代码为object.c,本文尝试从整体到局部来尝试解读其设计思想。object.c这个子系统从外部以黑盒的角度看,就个人理解主要实现了这样些用例需求:

所以个人理解内核对象管理器,主要是为其他内核功能模块提供数据管理支撑,属于内核底层支持功能组件,并从设计上兼顾了可扩展、可裁剪的需求。

怎么实现的呢?

RT-Thread内核对象子系统其主要核心数据结构如下:

其中rt_object_class_type枚举定义内核对象类别:

enum rt_object_class_type
{
    RT_Object_Class_Null   = 0,   /* 未使用        */
    RT_Object_Class_Thread,       /* thread对象    */
    RT_Object_Class_Semaphore,    /* semaphore对象 */
    RT_Object_Class_Mutex,        /* mutex对象     */
    RT_Object_Class_Event,        /* event对象     */
    RT_Object_Class_MailBox,      /* mail box对象  */
    RT_Object_Class_MessageQueue, /* message queue */
    RT_Object_Class_MemHeap,      /* memory heap   */
    RT_Object_Class_MemPool,      /* memory pool   */
    RT_Object_Class_Device,       /* device对象     */
    RT_Object_Class_Timer,        /* timer对象      */
    RT_Object_Class_Module,       /* module        */
    RT_Object_Class_Unknown,      /* unknown       */
    RT_Object_Class_Static = 0x80 /*8位类型变量高位置1表示静态对象 */
};

而rt_object_information则抽象了对象类型,加入了一个双向链表指针数据域rt_list_node,从而将同类别的内核对象利用该双链指针链接起来,这些同类别的内核对象具有如下可能的特点:

  • 可能在软件运行时生成,也可能在os初始化创建。
  • 其存储类型可能为静态类型,也可能为动态类型(所谓动态类型这里是确指在内核堆上动态申请的内存区域用于存储相应的内核对象)。
  • 在内存空间中,其位置并不连续。

如此以来,将这些内核对象在空间上不连续的变量,利用链表形成了可统一管理、可增可删、可检索的逻辑结构。

而rt_object_container内核容器,其本质是一个内核对象索引表,主要集中管理了下面的信息:

  • enum rt_object_class_type type:内核对象类别,每项表记录条目的类别
  • rt_list_t     object_list:每类对象链表的头结点的链表指针数据域
  • rt_size_t    object_size:该类个体的大小

利用宏将相应的链表进行选编译,在内核关键数据进行了裁剪管理。而对于内核本身的扩展性而言,如果需要增加新的内核功能,可以方便的增加新的内核对象类,并能方便的加入到这个内核对象容器中,利用公共的对外接口,实现统一管理,而不必对数据管理层进行额外的接口设计。

实现了哪些对外接口呢?

有了这样一个优雅的数据结构设计,那么基于这样一个数据结构设计,相应就很容易实现其内核对象集中管理的对外服务接口,那么其主要的服务接口有哪些呢?

其中一部分主要接口实现对象的增加\删除\检索等,这里以rt_object_init接口为例,来简要分析一下其实现:

void rt_object_init(struct rt_object         *object,                    enum rt_object_class_type type,                    const char               *name){    register rt_base_t temp;    struct rt_list_node *node = RT_NULL;    struct rt_object_information *information;#ifdef RT_USING_MODULE    struct rt_dlmodule *module = dlmodule_self();#endif

    /*1. 在容器中找到这是什么对象类*/    information = rt_object_get_information(type);    RT_ASSERT(information != RT_NULL);

    /* check object type to avoid re-initialization */

    /* 进入临界区保护 */    rt_enter_critical();    /* try to find object */    for (node  = information->object_list.next;            node != &(information->object_list);            node  = node->next)    {        struct rt_object *obj;

        obj = rt_list_entry(node, struct rt_object, list);        if (obj) /* skip warning when disable debug */        {            RT_ASSERT(obj != object);        }    }    /* 离开临界区 */    rt_exit_critical();

    /* 初始化对象参数,并置为静态标记 */     object->type = type | RT_Object_Class_Static;    rt_strncpy(object->name, name, RT_NAME_MAX);

    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));

    /* 禁止硬件中断 */    temp = rt_hw_interrupt_disable();

#ifdef RT_USING_MODULE    if (module)    {        rt_list_insert_after(&(module->object_list), &(object->list));        object->module_id = (void *)module;    }    else#endif    {        /* 对象插入容器中相应对象分支链连 */        rt_list_insert_after(&(information->object_list), &(object->list));    }

    /* 开硬件中断 */    rt_hw_interrupt_enable(temp);}
  • 对于内核对象增加\删除其主要就是利用内核容器首先检索到链表头结点,然后再进一步做双向链表的基本操作,这里对于具体如何操作链表就不做展开赘述了。
  • 对于内核对象相关数据域的检索、查询有了明确的数据结构,以及能检索到结点链表指针,由于结点链表指针与相应内核对象各数据域具有确定的相对位置关系,所以检索而言是非常易于实现的。

而对于动态内核对象而言,其差异在于内核对象本身是动态申请的,这里需要注意的是向内核堆申请的,而不是C堆申请的。

内核对象有什么相互继承关系?

RT-Thread官网上给出了这样一个相互关系图:

RT-Thread 内核对象继承关系

如果不去具体看相应数据结构,或许不易理解为啥有这样一张图。这里以上图中其中几个内核对象来撸一撸其相互关系:

或许有盆友会问,为啥rt_thread对象中明明没有直接包含rt_object,那为啥说rt_thread也是继承自rt_object呢?如果你细看看上图rt_thread中红框框出来的数据域就恍然大悟了,即便没有直接包含,但在内存中框里的内容就是rt_object的数据内容,所以利用指针转换就可以方便访问了,至于为什么是这样?我想可能是历史原因吧?所以rt_thread结构体前面几个数据域的相对位置是不可以修改的。这里还有盆友可能会问为什么ipc线程通信相关内核对象需要单独拎出来一个父结构体呢?我想应该是此类具有相同的一些共性,具有一些类似的特点。这也是对象设计提取共性进而抽象封装的一个体现。

总结一下

本文大致学习总结了一下RT-Thread内核对象子系统的设计思路的理解,从这里个人总结了一些启示:

  • 软件是数据结构+算法,而良好的数据结构设计是优雅算法的基础,所以在工程开发中,如何设计好的数据结构抽象是一个可以深入挖掘的话题
  • RT-Thread的内核对象设计个人认为非常易于理解,也是一个最佳实践。如有兴趣可以细细体会,多多揣摩。
(0)

相关推荐

  • 【RT-Thread笔记】对象容器与双链表

    前言 在我们嵌入式中,可能会有些人认为数据结构与算法相关知识没什么用,很少用得上. 以前,我也是这么认为的,那东西那么难学,好像又用不上,学了有什么用,干脆就不学了. 直到后面深入学习一些东西之后发现 ...

  • 自制IOC容器(2)

    本系列文章介绍ByxContainer的实现思路. ByxContainer是一个简单的轻量级IOC容器,具有以下特性: 使用JSON格式的配置文件 支持构造函数注入.静态工厂注入.实例工厂注入.属性 ...

  • 视频教程 | 新版RTOS教程:15天入门RT-Thread内核

    EEWorld 电子资讯 犀利解读 技术干货 每日更新       RT-Thread是国内优秀的物联网操作系统,拥有良好的生态基础和数10万的开发者群体,乃良心国货也~ 本教程由RT-Thread官 ...

  • Java之ThreadLocal

    Java之ThreadLocal

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

    RT-Thread中的对象有哪些? RT-Thread包括了很多不同类型的对象,如线程,信号量,互斥量等.在代码中,这些对象被汇总到一个枚举中(在rtdef.h中): 左右滑动查看全部代码>&g ...

  • 【干货】扒一扒辅料的那些事

    (每周一,四晚9点推送一篇干货) 做为一名合格的服装设计师,对辅料的运用是一定要了如指掌的,就好比一名出色的厨师,如果对自己要用的调味料有什么种类,有哪些特点都不知道,很难想象能做出什么美味的佳肴出来 ...

  • 验资50万,保利翔龙天汇究竟长啥样?我去扒了扒

    前两天,房产君的老友郭胖,约我去看一个黄埔全新盘,还神秘兮兮的说,这个盘,相当的牛,要不是托了他二舅老爷的邻居的外孙女的妈妈的堂姐的关系,还看不了. 呦呵,这么神秘的,那我这个踩盘小能手,必须去会会, ...

  • 肿瘤、心脑血管疾病、痴呆、新生儿畸形……扒一扒吸烟的危害到底有多大?

    大家都知道 吸烟对"肺"不好 如果你认为吸烟只是伤肺 那可就错了 吸烟的危害可远不止于此 -- 数据显示,我国吸烟人数超过3亿,15岁及以上人群吸烟率为26.6%,其中成年男性吸烟 ...

  • 收藏 | 扒一扒西欧喷气式战斗机家族谱合辑(上)

    孙磊东/文 噔噔噔 春节前夕, 航知贴心为大家汇总了20年发过的 苏霍伊战斗机家族谱合辑 今天, 我们继续汇总西欧喷气式战机家族谱 供大家收藏! 话不多说,就在下文↓ 西欧喷气式战斗机的历史 上图中的 ...

  • 收藏 | 扒一扒西欧喷气式战斗机家族谱合辑 (下)

    孙磊东/文 18 1958年 菲亚特G.91战斗轰炸机 菲亚特公司出品,英文名称Fiat G.91,是意大利应北大西洋公约组织要求所研制的一种轻型攻击机,也是二战结束后意大利首次自行研制的亚音速喷气式 ...

  • 单月壕掷16亿,我们扒了扒B站游戏投资版图的秘密

    下个航向.文/依光流&灰信鸽去年到今年业内资本动作频繁,其中出手投资最多的三家业内厂商,便是腾讯.IGG和B站.这三家当中,B站的资本动作相对特殊一些,带着更强的平台属性.也牵动着当下年轻人市 ...

  • 扒一扒质量管理中的十个常见“误区”

    质量管理中的十个常见"误区": 01 片面依赖于事后把关 质量部门,就是单纯的质量检验部门,只有质量检验功能,而没有质量管理体系保持功能,更加没有质量改进和完善功能.质量部门只负责 ...

  • 非得从零开始学习?扒一扒强化学习的致命缺陷

    大数据文摘编译作品 作者:Andrey Kurenkov 编译:Hope.爽爽.茶西.halcyon Deepmind在Alphago上的成就把强化学习这一方法带入了人工智能的主流学习领域,[从零开始 ...

  • 明星和大佬扎堆抢购上海市中心豪宅,扒一扒公司买房的税务秘密

    4月10日上海市东方公证处公布了翠湖天地隽荟的摇号排序全名单,总共385组认筹客户,购买118套预售房源.其中,单位客户214组,持中国大陆身份证购买的客户125组,非中国境内客户46组.(可以到这里 ...