多线程是实时操作系统外面最重要的知识点之一,要学习 RTOS,多线程是必须(没错,是必须)要熟练掌握的内容,只有熟练掌握多线程的应用,能力在平时的我的项目工作外面用好实时操作系统。
对于多线程的应用和治理,RT-Thread 官网提供了比拟丰盛的文档作为参考,具体能够查看以下链接:https://www.rt-thread.org/doc…,本文是对 RT-Thread 多线程学习后的总结,并尝试从如图所示的以下几个方面进行总结。
什么是多线程?
在单片机上学习 RT-Thread 的多线程之前,要先把“过程”这个概念先放一边,因为单片机是没有多过程概念的。单片机运行操作系统,不论多少个工作,他们都是多个(或单个)线程之间进行解决这些工作,单片机个别不波及多过程。
什么是多线程?在哪些状况下要用到多线程?先来举一个音乐播放器的例子,这个音乐播放器要做以下这些根本的工作:读取音乐文件并播放、读取歌词并显示、读取 MV 文件并播放。
如果这三个根本的工作不必多线程来实现,单片机应用裸机的形式去做这三个工作的话,必然会造成音乐播放卡顿,歌词显示不同步,MV 视频播放与音乐不同步。
因为单片机做这三件事件的时候,是 Step by Step 的,必须实现一件事件之后,再去做下一件事件,这三件事件是有先后顺序的,并且一直循环反复,如下图所示。
而如果采纳多线程这种形式来实现这个工作,这个过程就变得绝对简略了,比方针对音乐播放器这个场景,能够设计这几个线程来解决:音乐文件读取线程,歌词文件读取线程,MV 文件读取线程,音视频和歌词显示线程。
(此处只为举例形容多线程的概念,不思考音视频编解码的简单过程,不思考线程同步,实际上音乐播放器的实现比此处形容更简单)
音乐文件读取线程只负责从磁盘读取音乐文件,歌词文件读取线程和 MV 文件读取线程也是同样的情理,它们只做文件读取工作,而音视频和歌词显示线程,是负责把读取到的数据进行显示。这几个线程的工作过程,如下图所示。
如上图所示,这几个工作看上去是“同时”进行的,每个工作都只实现本人的事件,通过多线程,就能够把本来串行实现的工作改为并行实现,大大提高了工作效率。
所以,艰深地对多线程进行了解,就是把一个比拟大型的工作,拆分为多个小型的工作,而后通过正当的调度形式,让这几个小型的工作“同时”运行,当这几个小型工作实现后,大型的工作也随之实现,这样能够大大提高工作的实现效率。
多线程的几种状态
对于运行 RT-Thread 操作系统,线程都处于以下五种状态的其中一种(初始状态、就绪状态、运行状态、挂起状态、敞开状态),通过调用操作系统提供的接口函数,能够让线程在这五种状态中进行来回切换。
对于这五种线程状态的形容,如下表所示:
多线程的 API 函数
如上图的状态机所示,多线程能够通过调用零碎提供的函数接口,在多个状态之间进行切换。这些 API 函数在官网提供的参考文档外面都有具体的阐明形容,以下列举一些比拟罕用的函数接口。
多线程的利用示例
多线程的利用示例,次要是为了验证以上的多线程 API 接口函数,并且通过试验景象察看多线程的运行状况,次要有以下三个示例:
示例源码下载链接:https://github.com/embediot/r…
1、线程动态创建与动态创立、线程退出示例。
这个示例次要是通过动静形式创立线程 1,, 通过动态形式创立线程 2,线程 1 的优先级比线程 2 的优先级低,因而能够被线程 2 抢占。线程 2 运行 10 次后就会被动退出,初始化代码如下图所示。
2、雷同优先级线程的工夫片轮转调度示例。
这个示例次要是通过动静形式创立线程 1 和线程 2,这两个线程都是雷同的优先级,并且共用一个线程入口函数,次要是通过传入不同的线程参数以辨别线程 1 和线程 2。线程 2 运行所占用的工夫片比线程 1 要少,因而线程 2 运行的工夫比拟短,初始化代码如下图所示。
3、线程调度器的钩子函数应用示例。
这个示例次要测试了线程在进行调度时,对于钩子函数的调用状况。通过线程调度器的钩子函数,打印出线程间的切换信息,初始化的代码如下图所示。
多线程利用的注意事项
在应用 RT-Thread 实时操作系统进行多线程利用开发的时候,应该要留神以下事项:
1.RT-Thread 的线程调度器是抢占式的,也就是可能保障就绪队列外面,最高优先级的工作总能取得 CPU 的使用权,在工作设计的时候,要充分考虑好工作的优先级。
2. 在硬件中断服务程序运行期间,如果有高优先级的工作就绪,那么被中断的低优先级工作将被挂起,高优先级的工作将会取得 CPU 的使用权。
3. 每个线程都有独立的线程栈,用来保留线程调度时上下文的信息,因而在创立线程调配栈空间的时候,要充分考虑栈的大小。
4. 在线程的循环体外面,应该要设置某些条件,在必要的时候被动让出 CPU 的使用权,特地对于高优先级的线程,如果程序外面有死循环操作而又不被动让出 CPU 使用权,那么这个线程将会始终占用 CPU,并且低优先级的线程永远不会被调度执行。
5. 对于没有始终循环执行的线程,线程执行结束后,资源的回收状况实际上是在闲暇线程外面进行的,线程变为敞开状态后,不代表资源马上被回收。
6. 零碎闲暇线程是最低优先级且永远为就绪状态的,闲暇线程是一个死循环,永远不会被挂起,但能够被其余高优先级工作抢占,闲暇线程次要执行僵尸线程的资源回收工作。
7. 闲暇线程也能够设置钩子函数,用来进行功耗治理,看门狗喂狗等工作。
8. 通过动静形式创立的线程,须要设置好零碎堆内存的大小,而通过动态形式创立的线程,线程栈和线程句柄在程序编译的时候就曾经确定,不能被动态分配,也不能被开释。
9. 大多数线程都是在一直循环执行的,无需进行删除,个别不举荐被动删除线程。线程运行结束后,系统调度器将会主动把线程退出僵尸队列,资源回收工作将在闲暇线程外面进行。
感激浏览!
原文链接:https://club.rt-thread.org/as…