最新文�? 转载 : C++中常用的四种类型转换方式:static_cast、const_cast、dynamic_cast 和 reinterpret_cast 原创 : GB 9706.1-2020新标准新法规下载与讨论 原创 : 《CPU设计实战》——学习之路(一) 原创 : 不同方法构建PetaLinux系统 原创 : 无损检测技术之医用超声基础
原创 : 来扒一扒秀秀的RT-Thread内核对象管理器设计思路 历史版本:
上次修改时间:

引用自

原创 : 来扒一扒秀秀的RT-Thread内核对象管理器设计思路

来扒一扒秀秀的RT-Thread内核对象管理器设计思路

关注、星标嵌入式客栈,精彩及时送达

[导读]  前面写了些文章分享C语言面向对象设计的一些个人体会,个人认为RT-Thread内核对于面向对象实现思想是一个非常好的设计。向这些在基础软件上深耕的国人大牛们致敬。本文基于学习RT-Thread内核设计的初衷,来分享一下个人对于其内核对象子系统设计的理解与体会。在此,也给各位RT-Thread原创大牛们打call,分享本文也期望有更多的盆友去学习并使用RT_Thread。

RT-Tread内核架构

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

RT-Thread 内核及底层结构

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

所以如果是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,从而将同类别的内核对象利用该双链指针链接起来,这些同类别的内核对象具有如下可能的特点:

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

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

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

实现了哪些对外接口呢?

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

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

总结一下

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

****END

往期精彩推荐,点击即可阅读

▲Linux驱动相关专辑** **

手把手教信号处理专辑

片机相关专辑

0条评�?
全部评论

关于博主

an actually real engineer

通信工程专业毕业,7年开发经验

技术栈:

精通c/c++

精通golang

熟悉常见的脚本,js,lua,python,php

熟悉电路基础,嵌入式,单片机

耕耘领域:

服务端开发

嵌入式开发

git

>

gin接口代码CURD生成工具

sql ddl to struct and markdown,将sql表自动化生成代码内对应的结构体和markdown表格格式,节省宝贵的时间。

输入ddl:
输出代码:

qt .ui文件转css文件

duilib xml 自动生成绑定控件代码

协议调试器

基于lua虚拟机的的协议调试器软件 支持的协议有:

串口

tcp客户端/服务端

udp 组播/udp节点

tcp websocket 客户端/服务端

软件界面

使用例子: 通过脚本来获得接收到的数据并写入文件和展示在界面上

下载地址和源码

duilib版本源码 qt qml版本源码 二进制包

webrtc easy demo

webrtc c++ native 库 demo 实现功能:

基于QT

webrtc摄像头/桌面捕获功能

opengl渲染/多播放窗格管理

janus meeting room

下载地址和源码

源码 二进制包

wifi,蓝牙 - 无线开关

实现功能:

通过wifi/蓝牙实现远程开关电器或者其他电子设备

电路原理图:

实物图:

深度学习验证工具

vtk+pcl 点云编辑工具

实现功能:

1. 点云文件加载显示(.pcd obj stl)

2. 点云重建

3. 点云三角化

4. 点云缩放

下载地址:

源码 二进制包

虚拟示波器

硬件实物图:

实现原理

基本性能

采集频率: 取决于外部adc模块和ebaz4205矿板的以太网接口速率,最高可以达到100M/8 约为12.5MPS

上位机实现功能: 采集,显示波形,存储wave文件。

参数可运行时配置

上位机:

显示缓冲区大小可调

刷新率可调节

触发显示刷新可调节

进程守护工具

基本功能:

1. 守护进程,被守护程序崩溃后自动重启。

2. 进程输出获取,显示在编辑框中。

二进制包

openblt 烧录工具

基本功能:

1. 加载openblt 文件,下载到具有openblt bootloader 运行的单片机中。

二进制包

opencv 功能验证工具(开源项目二次开发)

基本功能:

1. 插件化图像处理流程,支持自定义图像处理流程。 2. 完善的日志和权限管理

二进制包

又一个modbus调试工具

最近混迹物联网企业,发现目前缺少一个简易可用的modbus调试工具,本软件旨在为开发者提供一个简单modbus测试工具。
主打一个代码简单易修改。
特点:

1. 基于QT5

2. 基于libmodbus

3. 三方库完全跨平台,linux/windows。

二进制包

屏幕录制工具

1. 基于QT5

2. 基于ffmpeg

3. 支持自定义录屏

源代码

开源plutosdr 板卡

1. 完全开源

2. 提高固件定制服务

3. 硬件售价450 手焊产量有线

测试数据

内部DDS回环测试

接收测试

外部发送500MHZ FM波形

硬件原理图

matlab测试

2TRX版本

大部分plutosdr应用场景都是讲plutosdr板卡作为射频收发器来使用。
实际上plutosdr板卡本身运行linux 操作系统。是具有一定脱机运算的能力。 对于一些微型频谱检测,简单射频信号收发等应用完全可以将应用层直接实现在板卡上
相较于通过网卡或者USB口传输具有更稳定,带宽更高等优点。
本开源板卡由于了SD卡启动,较原版pluto支持了自定义启动应用的功能。
提供了应用层开发SDK(编译器,buildroot文件系统)。
通过usb连接电脑,经过RNDIS驱动可以近似为通过网卡连接
(支持固件的开发定制)。

二次开发例子

``` all:
arm-linux-gnueabihf-gcc -mfloat-abi=hard --sysroot=/root/v0.32_2trx/buildroot/output/staging -std=gnu99 -g -o pluto_stream ad9361-iiostream.c -lpthread -liio -lm -Wall -Wextra -lrt
clean:
rm pluto_stream

bsdiff算法补丁生成器

1. 官方bsdiff算法例子自带bzip压缩方式

2. 本例子没有压缩,直接生成补丁文件

3. 图形化界面基于DUILIB

二进制文件

版面分析即分析出图片内的具体文件元素,如文档标题,文档内容,文档页码等,本工具基于cnstd模型

Base64 Image

. 闽ICP备19002644号