内核各个文件
| 文件名 | 作用 |
|---|---|
| kservice.c | 内核库、提供c库的函数 |
| object.c | 对象管理 |
| schedule.c | 实时调度器 |
| thread.c | 线程管理 |
| ipc.c | 线程间通信 |
| clock.c、timer.c | 时钟管理 |
| mem.c等 | 内存管理 |
| device.c | 设备管理 |
RT-Thread程序内存分布
- code:代码段,存放程序代码
- RO-data:只读数据段,存放程序中定义的常量 const;
- RW-data:读写程序段,存放初始化为非0的全局变量 static
- ZI-data:零数据段,存放未初始化的全局变量及初始化为0的变量
线程管理
功能特点
- 抢占式线程调度器,从就绪列表中找到优先级最高的线程,保证优先级最高的线程能够被运行,最高优先的线程一旦就绪,总能得到CPU的使用权
- 一个运行着的线程使一个比它优先级高的线程满足运行条件,就会让出使用权
- 中断服务程序使一个高优先级的线程满足运行条件,中断完成时,被中断的线程挂起,优先级高的线程开始运行
- 当线程调度器线程切换时,先将当前线程上下文保存起来,当再切回到这个线程时,线程调度器恢复该线程上下文信息
线程工作机制
线程控制块
使用struct rt_thread表示,线程控制块是操作系统用于管理线程的数据结构;
存放一些线程信息:优先级、线程名称、线程状态等;
还包含线程间连接的链表结构,事件等集合。
线程重要属性
线程栈
- 进行线程切换时,会将当前线程的上下文保存在栈中,当线程恢复运行时,再从栈中读取上下文信息,进行恢复
- 线程栈还用于存放函数中的局部变量
线程状态
- 初始状态
- 就绪状态
- 运行状态
- 挂起状态
- 关闭状态
线程优先级
- 表示线程被调度的优先程度。
- 最大支持256个优先级。在CM系列中,常用32个优先级。
- 最低优先级的线程默认分配给空闲线程使用。
时间片
- 每个线程都有时间片,但时间片仅对优先级相同的线程有效。
- 系统对优先级相同的就绪状态线程采用时间片轮转的方式调度
- 时间片起着约束线程单次运行时长的作用,单位是
OS tick
线程入口函数
线程控制块中entry是线程的入口函数,他是线程实现预期功能的函数。线程入口函数有用户设计实现
无线循环模式
1
2
3
4
5
6
7
8void thread_entry(void * parameter)
{
while(1)
{
/* 等待时间发生 */
/* 对事件进行服务、处理 */
}
}不能进入死循环模式,必须有让出CPU使用权的操作,如:循环中调用延时或者主动挂起。
顺序执行或有限次循环
1
2
3
4static void thread_entry(void*parameter)
{
}由系统自动删除
线程错误码
1
2
3
4
5
6
7
8
9
10
11
线程状态切换

线程通过调用函数
rt_thread_create/init()进入到初始状态RT_THREAD_INIT;初始状态的线程通过调用函数
rt_thread_startup()进入到就绪状态RT_THREAD_READY;就绪状态的线程被调度器调度后进入运行状态
RT_THREAD_RUNNING;处于运行状态的线程调用
rt_thread_delay()、rt_sem_take()、rt_mutex_take()、rt_mb_rev()等函数或者获取不到资源时,将进入挂起状态RT_THREAD_SUSPEND处于挂起状态的线程,如果等待超时或者未能获得资源或由于其他线程释放了资源,那么他将回到就绪状态。调用
rt_thread_delete/detach()函数,将更改为关闭状态RT_THREAD_CLOSE;运行状态的线程,如果运行结束,就会在线程的最后部分执行
rt_thread_exit()函数,将状态更改为关闭状态注意! RT-Thread中实际上不存在运行状态,就绪状态和运行状态是等同的。
系统线程
系统线程是指由系统创建的线程,用户线程是有用户程序调用线程管理接口创建的线程,在RT-Thread内核中的系统线程有空闲线程与主线程。
空闲线程
空闲线程是系统创建的优先级最低的一个线程,永远为就绪状态。
当系统中无其他就绪线程时,调度器将调度到空闲线程,它通常是个死循环,且永远不被挂起。
在RTT中有特殊用途:
- 若某线程执行完毕,系统将自动删除线程:自动执行
rt_thread_exit()函数,先将该线程从系统就绪队列中删除,再将该线程状态改为关闭状态,不再参与系统调度,然后挂入rt_thread_defunct僵尸队列(资源未回收,处于关闭状态的线程队列)中,最后空闲线程会回收被删除线程的资源。 - 运行用户设置的钩子函数,在空闲线程运行时会调用该钩子函数,适合钩入功耗管理、看门狗喂狗等工作
主线程
- 系统启动时,系统会创建main线程,入口函数为
main_thread_entry(),用户的应用入口函数main()从这里真正开始,用户可以在main()函数中添加自己的初始化代码
线程管理的方式
创建动态线程 rt_thread_create() 创建静态线程 rt_thread_init()
创建和删除线程
一个线程要成为可执行的对象,就必须由操作系统的内核来为它创建一个线程。
1 | rt_thread_t rt_thread_create(const char*name, |
系统会从动态堆内存中分配一个线程句柄,以及按照参数中指定的栈大小分配相应的空间
| 参数 | 描述 |
|---|---|
| name | 线程的名称;线程名称的最大长度由rtconfig.h中的宏RT_NAME_MAX定义,多余部分会自动截掉 |
| entry | 线程入口函数 |
| parameter | 线程入口函数参数 |
| stack_size | 线程栈大小,单位是字节 |
| priority | 线程的优先级。优先级范围根据系统配置情况(rtconfig.h中的RT_THREAD_PRIORITY_MAX定义),如果支持的是256级优先级,那么范围是从0~255,数值越小优先级越高,0代表最高优先级 |
| tick | 线程时间片大小。时间片的单位是操作系统的时钟节拍。当系统中存在相同优先级的线程时,这个参数指定线程一次调度能够运行的最大时间长度。这个时间片运行结束时,调度器自动选择下一个就绪态的同优先级线程进行运行 |
| 返回 | |
| thread | 线程创建成功,返回线程句柄 |
| RT_NULL | 线程创建失败 |
对于使用rt_thread_create()创建出来的线程,当不需要使用,或者运行出错是,可以使用下面的函数接口来从系统中把线程完全删除掉:
rt_err_t rt_thread_delete(rt_thread_t thread)
调用该函数后,线程对象会被移出线程队列,并且从内核对象中删除,释放掉线程占用的堆栈空间,收回来将用于其他内存分配。
注意:rt_thread_delete()是将thread变为CLOSE状态,放入rt_thread_defunct队列中;真正的删除动作(释放线程和释放线程栈)需要到下一次执行空闲线程时,由空闲线程完成最后的线程删除动作。