物联网系统RT-Thread学习---内核学习

Posted 胖哥王老师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了物联网系统RT-Thread学习---内核学习相关的知识,希望对你有一定的参考价值。

上集回顾

《物联网系统RT-Thread学习—开发环境搭建》

本集预告

内核部分的介绍,在官方的文档中,介绍的巨细无比:
RT-Thread文档中心
所以这里就介绍一些概念和值得注意的内容。更像是我读了文档中心的一些理解

前戏

介绍一下工程的配置方法,可以通过图形化的界面,配置你的系统内核,组件,软件包和硬件参数,简直不能太美丽。

实际上是一种menuconfig的图形化表示,目录中的kconfig文件格式,与linux的内核配置是基本是一样的。

线程

RT-Thread操作系统是基于线程调度的多任务系统。

  • 调度过程是一种完全抢占式的基于优先级的调度算法,即在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身。
  • 支持8/32/256优先级,其中0表示最高,7/31/255表示最低。最低优先级7/31/255优先级用于空闲线程。
  • 支持以相同优先级运行的线程。 共享时间片循环调度用于这种情况。
  • 线程包含五种状态,操作系统会自动根据它运行的情况来动态调整它的状态。

我用的开发板是STM32的开发板,在rtconfig.h中,可以定义优先级的参数,默认为32个优先级。

创建线程

RTT的线程分为动态线程和静态线程,静态线程创建

rt_err_t rt_thread_init(struct rt_thread* thread,
                        const char* name,
                        void (*entry)(void* parameter), void* parameter,
                        void* stack_start, rt_uint32_t stack_size,
                        rt_uint8_t priority, rt_uint32_t tick);

动态线程创建

rt_thread_t rt_thread_create(const char* name,
                            void (*entry)(void* parameter),
                            void* parameter,
                            rt_uint32_t stack_size,
                            rt_uint8_t priority,
                            rt_uint32_t tick);

二者创建之后,都需要执行

rt_err_t rt_thread_startup(rt_thread_t thread);

来启动线程。
这两种有什么区别呢?

静态方式的时候,需要注意的是,用户提供的栈首地址需做系统对齐(例如 ARM 上需要做 4 字节对齐)
这就是代码中这里的含义

ALIGN(RT_ALIGN_SIZE) //字节对齐
static char thread2_stack[1024];
static struct rt_thread thread2;

一般人我不告诉他

让出CPU

这里有两个函数rt_thread_yield() 函数和 rt_schedule(),前者就是自己会让出CPU,并且重新跑到队尾去排队,而后者是让出CPU,但是不会重新去排队,所以在有相同优先级的线程时候,会有运行的差别。

时间管理

时钟节拍

这个概念就是系统的心跳,时间的最小单位,任务执行的最小时间吧,在STM32F103中默认的时钟节拍是每秒1000次,也就是最小的时间颗粒是1ms

如果要做一些更细微的事情呢,就需要参考高精度延时了。

定时器

分为一次性,周期性,软件定时和硬件定时,创建方式和前面的线程一样,分为动态和静态方式,创建之后也需要手动启动。

线程间同步

这里主要讲一下事件集,简单来说就是一个32位数字,每一位都可以代表一个事件,有的线程可以修改事件,有的线程可以选择监听事件某个或者某些事件,并且事件集可以用来一对多的进行消息同步,这个和FreeRTOS的事件组是一样的东西。
FreeRTOS事件组内容
打了个广告

线程间通讯

同步是传递0与1的值,来控制不同程序按照不同步骤运行,通讯则是传递消息,用来将数据从一个线程,共享到另一个或者几个线程。
消息队列和邮箱,都和μC/OS II中的一样,也是用来传递多个指针和单个指针的内存数据。对μC/OS II感兴趣的话,可以参考我的另一篇文章
《μC/OS-II学习–使用篇(一篇就足够了)》
这里重点介绍一下一种通讯方式

信号

这个和信号量不一样,信号量是等来的,这个信号,是一种中断,不知道什么时候,它就来了。

信号本质是软中断,用来通知线程发生了异步事件,用做线程之间的异常通知、应急处理。一个线程不必通过任何操作来等待信号的到达,事实上,线程也不知道信号到底什么时候到达,线程之间可以互相通过调用 rt_thread_kill() 发送软中断信号。

这与linux中的signal是一样的,线程可以注册一个函数,用来执行用户消息,当有另外的线程发送这个信号给此线程的时候,线程就会去执行那个函数,用来处理响应。

不过默认的STM32小蓝板的工程,默认并不支持signal,通过以下方式打开

内存管理

内存堆管理

内存堆管理用于管理一段连续的内存空间,有以下三种方法

方法特点
小内存管理算法主要针对系统资源比较少,一般用于小于 2MB 内存空间的系统
slab 内存管理算法主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速算法
memheap 方法适用于系统存在多个内存堆的情况,它可以将多个内存 “粘贴” 在一起,形成一个大的内存堆,用户使用起来会非常方便。

STM32默认的是小内存管理法。说白了还是资源不足啊。

内存池管理

内存池是一种内存分配方式,用于分配大量大小相同的小内存块,它可以极大地加快内存分配与释放的速度,且能尽量避免内存碎片化。此外,RT-Thread 的内存池支持线程挂起功能,当内存池中无空闲内存块时,申请线程会被挂起,直到内存池中有新的可用内存块,再将挂起的申请线程唤醒。

中断管理

在访问临界资源的时候,可以用下面方法

/* 关闭全局中断 */
level = rt_hw_interrupt_disable();
cnt += no;
/* 恢复全局中断 */
rt_hw_interrupt_enable(level);

结束语

RTT的内核,集百家所长,借鉴了FreeRTOS,linux,μC/OS中的各种有价值的东西,并且提供了更为有价值的组件和软件包,配合一个优秀的Studio,绝对是当前物联网开发的神兵利器。

以上是关于物联网系统RT-Thread学习---内核学习的主要内容,如果未能解决你的问题,请参考以下文章

物联网操作系统一站式开发工具:RT-Thread Studio

强烈推荐一款国产物联网实时操作系统RT-Thread

强烈推荐一款国产物联网实时操作系统RT-Thread

RT-Thread 内核学习笔记 - 内核对象操作API

RT-Thread 内核学习笔记 - 理解defunct僵尸线程

RT-Thread与EMQ合作搞物联网