文章目录

  • 前置说明
  • RTThread框架
  • 线程管理及调度器
  • 线程间通信管理
  • 时钟管理
  • 内存分布
  • 内存管理
    • 动态内存堆管理
    • 静态内存池管理
  • RTT启动过程
  • 自动初始化机制
  • 内核对象管理架构
  • 内核配置&剪裁

前置说明

一般单片机一般只有一个核心,做多线程实际上是 分时复用 CPU,是并发的。线程通常是指操作系统上的概念,而本文介绍的实时操作系统 RTThread 的线程个人感觉应该称之为 任务 更合理,但为了和官方说法一致,以下仍叫线程。

主要参考: RTThread 内核基础

RTThread框架

与其他 RTOS 不同,RTThread 不仅仅是一个实时内核,它在努力构造一套开发生态。

RTThread(一) – 概念及简介-编程知识网

其完整版框架如下:

RTThread(一) – 概念及简介-编程知识网
当然这里我们仅学习 RTThread 内核 部分,同时本文大部分内容点到浅尝辄止,主要是对RTThread 有一个大体的印象。

RTThread(一) – 概念及简介-编程知识网

线程管理及调度器

RTT 的本质是 基于优先级的全抢占式多线程调度系统,在该实时系统中,线程是最小的调度单位。

即在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身。

RTThread(一) – 概念及简介-编程知识网
注意:RT-Thread 中,实际上线程并不存在运行状态,就绪状态和运行状态是等同的。

RTT 最多支持 256 个线程优先级,0 优先级代表最高优先级,最低优先级留给空闲线程使用。

同时它也支持创建多个具有相同优先级的线程,相同优先级的线程间采用 时间片轮转调度算法 进行调度,使每个线程运行相应时间。

线程间通信管理

  • 线程同步
    RT-Thread 采用 信号量互斥量事件集 实现线程间同步。线程通过对信号量、互斥量的获取与释放进行同步。
  • 线程通讯
    RT-Thread 支持 邮箱消息队列 等通信机制。邮箱和消息队列的发送动作可安全用于中断服务例程中。通信机制支持线程按优先级等待或按先进先出方式获取。

时钟管理

任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。

时钟节拍是特定的 周期性中断,这个中断可以看做是 系统心跳,中断之间的时间间隔取决于不同的应用,时钟节拍率越快,系统的额外开销就越大,从系统启动开始计数的时钟节拍数称为系统时间。

RT-Thread 的时钟管理以时钟节拍为基础,时钟节拍是 RT-Thread 操作系统中最小的时钟单位。

RT-Thread 的定时器提供两类定时器机制:

  • 单次触发定时器
    这类定时器在启动后只会触发一次定时器事件,然后定时器自动停止。
  • 周期触发定时器
    这类定时器会周期性的触发定时器事件,直到用户手动的停止定时器否则将永远持续执行下去。

通常使用定时器定时 回调函数(即超时函数),完成定时服务。用户根据自己对定时处理的实时性要求选择合适类型的定时器。

内存分布

首先看一下 RT-Thread Studio 中 编译完生成的 elf 文件:

RTThread(一) – 概念及简介-编程知识网

  • text
    代码段,用来存放 代码 及一些 只读常量,一般是只读的区域。

  • data
    数据段,用来存放全局初始化变量,以及全局或局部 静态变量

  • bss
    BSS 段,用来存放所有 未初始化的数据,用 0 来初始化。

  • dec
    decimal 即十进制的缩写,是 textdatabss 的算术和。

  • hex
    hexadecimal 即十六进制的缩写。

  • filename
    编译生成的目标文件名,本例中即为:rtthread.elf

一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM

RAM 相当于内存,Flash 相当于硬盘

  • FLASH(烧录程序所占的Flash大小) = text + data

  • RAM (运行时占用的RAM大小) = data + bss

RTThread(一) – 概念及简介-编程知识网

内存管理

动态内存堆管理

动态内存堆是根据我们开发需求分配任意大小的内存块。既然是堆,那么就要我们自己申请及释放。当不需要再使用这些内存块时,需要释放回堆中供其他应用分配使用,否则会造成 内存泄漏

RTT为我们提供了三种动态内存堆的调度算法:

  • 小内存管理算法
  • slab算法
  • memheap 管理算法

静态内存池管理

内存堆管理器非常灵活和方便,但是会产生以下两个问题:

  • 分配效率不高,在每次分配时,都要空闲内存块查找。
  • 容易产生内存碎片。

为了提高内存分配的效率,并且避免内存碎片,RT-Thread 提供了另外一种内存管理方法:内存池(Memory Pool)。

注意:内存池是 静态变量,其存放位置为 data 段。

RTThread(一) – 概念及简介-编程知识网

当静态内存池具有可用内存时,系统对内存块分配的时间将是恒定的。

当静态内存池为空时,系统将申请内存块的线程挂起或阻塞掉 (即线程等待一段时间后仍未获得内存块就放弃申请并返回,或者立刻返回。

等待的时间取决于申请内存块时设置的等待时间参数),当其他线程释放内存块到内存池时,如果有挂起的待分配内存块的线程存在的话,则系统会将这个线程唤醒。

ps:内存池的线程挂起功能非常适合需要通过内存资源进行同步的场景。

RTT启动过程

RTThread(一) – 概念及简介-编程知识网

自动初始化机制

在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。

使用该方法,main() 函数会非常简洁。

RTThread(一) – 概念及简介-编程知识网

内核对象管理架构

RT-Thread 采用内核对象管理系统来访问 / 管理所有内核对象,内核对象包含了内核中绝大部分设施,这些内核对象可以是静态分配的静态对象,也可以是从系统内存堆中分配的动态对象。

RTThread(一) – 概念及简介-编程知识网

通过这种内核对象的设计方式,RT-Thread 做到了不依赖于具体的内存分配方式,系统的灵活性得到极大的提高。对象容器中包含了每类内核对象的信息,包括对象类型,大小等。对象容器给每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上。

推荐:rt-thread的内核对象管理系统分析

内核配置&剪裁

RT-Thread 的一个重要特性是高度可裁剪性,支持对内核进行精细调整,对组件进行灵活拆卸。

配置主要是通过修改工程目录下的 rtconfig.h 文件来进行,用户可以通过打开 / 关闭该文件中的 宏定义 来对代码进行条件编译,最终达到系统配置和裁剪的目的。

另外,envmenuconfig 是个好东西。

注意:在实际应用中,系统配置文件 rtconfig.h 是由配置工具自动生成的,无需手动更改。