在上一篇博客中,简单介绍了一下RT-Thread,在这一篇博客中,记录了一下自己学习RT-Thread内核的基础内容,这部分内容的学习,主要是为了对RT-Thread内核做一个基本的了解,通过学习,应该了解到这么几部分:
- 内核的组成部分
- 系统是如何启动的
- 内存的分布情况
- 内核的配置方法
RT-Thread内核基础
这部分内容主要包括:
- [ 内核简介]
- [系统的启动流程]
- [内核的分布]
- [ 自动化初始机制]
- [内核的对象模型]
内核简介
内核部分包括了内核库以及实时内核的实现。RT-Thread的内核以及底层结构如图所示:
内核库是一套小型的类似于C库的函数实现子集。这一部分根据不同的编译器所带的C库的不同,也会有所差异。在使用GCC、GNU编译的时候,会携带更多的标准C库的实现。同时,为了并避免重名,RT-Thread的这些函数前都会加上rt_前缀加以区别。
对于实时内核,则包括了:对象管理、线程管理及调度器、线程间通信管理、时钟管理及内存管理等等
线程调度
在上篇博客中也提到了,RT-Thread的任务是通过线程实现的。所以线程也是RT-Thread操作系统的最小调度单位。对于线程的调度策略,采用的是基于优先级的全抢占式多线程调度算法。怎么理解呢?就是说除了以下几种情况,系统的其他线程均可以被优先级较高的线程抢占执行权。这几种情况分别为:
- 中断处理函数
- 调度器上锁部分的代码
- 禁止中断的代码
目前RT-Thread最高支持256个线程优先级,但是,最大线程优先级数也是可以通过配置文件自行配置的。在线程的优先级中,最高的优先级为0级,而最低的优先级(数值最大)需要留给空闲线程使用(具体为什么,以后的章节再做说明)。但是我们很难做到每一个线程都分配不同的优先级,因为总会存在具有相同优先级的任务需要去执行。这个时候,就把这些任务分配相同的优先级。而对于相同优先级的任务,采用的是时间片轮询的方法进行调度的。怎么理解呢?具体来讲就是这些具有相同优先级的线程,每个占用CPU的机会是轮着来的,到某个线程之后,就执行相应要求的时间,到时间之后,交出CPU执行权限,换下一个线程,依次轮询。另外调度器在寻找那些处于就绪状态的具有最高优先级的线程时,所经历的时间是恒定的,系统也不限制线程数量的多少,线程数目只和硬件平台的具体内存相关。
时钟管理
RT-Thread的时钟管理是以时钟节拍(该系统的最小时钟单位)为基础的。提供两种定时机制:
- 单次触发定时器:单次触发定时器事件,自动停止。
- 周期触发定时器:周期触发定时器事件,需要用户手动停止,否则一直执行下去。
根据超时函数执行所处的上下文环境,定时器可以设置为:HARD_TIMER模式和SOFT_TIMER模式。
线程同步
实现方法:信号量、互斥量与事件集实现线程间同步。
线程通过对信号量、互斥量的获取和释放进行同步。
其中,互斥量采用优先级继承解决了实时系统的优先级翻转问题(优先级翻转:假设有3个线程,线程A优先级为1,B为2,C为3,所以线程优先级排序:A>B>C。此时,A和B处于挂起状态,C正在运行,而此时C正在占用某一共享资源M,在C使用M资源的时候,A等的事件到来,则A转为就绪态,此时A线程抢占C的执行权限,开始执行。但是,A线程同样需要M资源,而M资源此时正被A线程占用,所以A只能等C执行完了(释放了M资源)才能继续执行,此时A就又被挂起了。好巧不巧,B线程等待的事件也到来了,而B的优先级又高于C,且不需要M资源,所以此时C线程的执行权限被B抢去了,直到B线程执行结束,C线程才能继续执行。而只有当C线程释放了M资源之后(可以假设释放了M资源,C线程也就结束了),A线程才能继续执行。这样一来,线程的执行完成顺序就变成了:B->C->A。此时这种情况就叫做优先级反转,这种情况就不能保证高优先级线程的响应时间了)。对于优先级的继承,将在线程同步的进一步学习中再做理解,这里只需要记住这个概念即可。
线程同步机制支持线程按照优先级等待或者按照先进先出的方法获取信号量或者互斥量。
线程通过对事件的发送和接受进行同步,事件集支持多事件的“或触发”以及“与触发”,适合线程等待多个事件的情况。
线程间通信
RT-Thread支持邮箱、消息队列等通信机制。两种方法的差别在于:邮箱机制,一封邮件长度固定4个字节大小;而消息队列支持不定长度的消息,并把消息缓存在自己的内存空间。效率方面:邮箱 > 消息队列。且两者都可以安全地用在中断中。
内存管理
RT-Thread支持静态内存池管理以及动态内存堆管理。
静态内存池管理:有内存就分配,否则等待,或者阻塞掉(等待超时,放弃申请)
动态内存堆管理:根据系统资源的不同,有面向小内存的管理方法,也有面向大内存的
I/O设备管理
RT-Thread将PIN、I2C、SPI、USB、UART等作为外设设备,并且统一通过设备注册完成。进而形成按照名称访问的设备管理子系统。根据嵌入式系统的特点,对于不同设备的驱动接口,可以挂接相应的响应事件。当设备上有事件触发时,由驱动程序将该动作传给上层应用程序。
今天就到这里了,下次继续学习内核基础相关内容。