Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
2024-RSOC
夏令营
星火1号_spark_星火一号_开发板
【2024-RSOC】RT-Thread分析线程内核学习分享(DAY2)
发布于 2024-07-25 01:37:34 浏览:606
订阅该版
[tocm] ## 实时系统 **实时系统是指在确定的时间内完成规定功能,并能对外部异步事件作出正确响应的计算机系统。** 分类: 硬实时系统、FIRM(严格)实时系统、软实时系统 在出现结果迟到的问题上,只有软实时系统影响最小 衡量实时性的指标 - 响应时间 (Response Time) - 生存时间(Survival Time) - 吞吐量(Throughput) ## 嵌入式实时系统 开发原则:尽量确保系统的正常运行不依赖于运行逻辑结果 系统对于各种外部输入在预定时间内能得到可预测的结果 RTOS - 在不同的系统负载下,行为可以预测 - 支持基于优先级的调度 - MEMORY模型对于RTOS的性能十分重要 - 通常都需要一个时钟来处理任务的同步 ## 嵌入式实时系统的几大特点 实时性 反应时间要快,按要求的间隔输出正确时间信号给实时的控制设备 快速启动 快速启动,并有出错处理和自动复位功能 多任务并发性 利用适当的策略控制多任务的执行,提高资源的利用效率 运行空间 嵌入式实时软件是应用程序和操作系统两种软件的一体化程序 异步事件 有处理异步事件的能力 开发方式 嵌入式实时软件的开发需要独立的开发平台和交叉开发环境 > uClinux:嵌入式Linux,结构复杂,移植难度大,实时性没那么好 ## 线程控制块 一个管理线程的一个结构体 ![image-20240724215927034.png](https://oss-club.rt-thread.org/uploads/20240725/7ff84a29da944c56d83bd29aa0309308.png) >线程控制块由结构体 struct rt_thread 定义并形成线程内核对象,再链接到内核对象容器中进行管理。 ![image-20240724145353277.png](https://oss-club.rt-thread.org/uploads/20240725/e538679aa58d34d55196d79a1e5133c1.png.webp) 线程继承自rt_object ## 线程属性-线程栈 - RT-Thread的线程具有独立的栈空间,当进行线程切换时,会将当前线程的上下文存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。 - 线程栈还用来存放函数中的局部变量:函数中的局部变量从线程栈空间中申请;初始时局部变量会从寄存器中分配(ARM架构),当这个函数再调用另一个函数时,这些局部变量将放入栈中。 - 线程栈的增长方向与芯片构架密切相关的,RT-Thread3.1.0以前的版本,均只支持栈由高地址向低地址的增长方式,对于ARM Cortex-M架构,线程栈可构造如右图所示。 ![image-20240724160148000.png](https://oss-club.rt-thread.org/uploads/20240725/0e7df8e7aac8ab41129507d4cbba5f0a.png.webp) ## RT-Thread启动流程 ![Pasted image 20240723191322.png](https://oss-club.rt-thread.org/uploads/20240725/c870f668040d350f72038c77be499199.png.webp) ## RT_Thread状态 ![image-20240724220543587.png](https://oss-club.rt-thread.org/uploads/20240725/f499a84059101c06774a15e8ad48d5b7.png.webp) ## RT-Thread启动流程分析 首先看下rtthread的启动文件startup_stm32f407xx.s 根据上图的描述,我们可以尝试在汇编文件里找到enrty(),并打下断点,编译运行,单步进入 发现rt-thread最开始启动函数原来藏这里了 ![image-20240724175427749.png](https://oss-club.rt-thread.org/uploads/20240725/4a5a17ca19d01f08eca1c98830d4e027.png) 这时在进入这个函数的定义就可以发现上图所有的函数都在里面了 ![image-20240724180334608.png](https://oss-club.rt-thread.org/uploads/20240725/8baa0a09f564f0b795824336811df46c.png.webp) 由于解释起来篇幅比较大所以感兴趣的读者可以自行跳转进去看一看 这里主要记录下main的线程是怎么运行的 ## Main线程调度 注意rt_application_init这个函数,查看下定义可以看到 ![image-20240724215346880.png](https://oss-club.rt-thread.org/uploads/20240725/760bb45622a96321a3329827f98b1b5e.png) init初始化创建了一个线程,然后startup启动了这个线程,看下这个创建线程的定义 ![image-20240724215807652.png](https://oss-club.rt-thread.org/uploads/20240725/ddf4cd234bcb8b30135260b552f066ad.png.webp) 首先是申请了一块上面提到的线程控制块中的rt_thread结构体内存 然后把结构体的内容通过_thread_init进行初始化,并将线程状态设为初始状态,以及线程其他内容的初始化 初始化的过程中还包括了线程栈的初始化,其中pc则是main线程的回调函数指针 ![image-20240724220051028.png](https://oss-club.rt-thread.org/uploads/20240725/edc08f54f80ea953ce5de39f22df2532.png) (读者可以尝试找下函数定义,试试看自己能不能找到这段) 然后是startup,这个函数内部主要做的是把线程从初始化转为就绪状态 接下来回到rtthread_startup下的rt_thread_idle_init()初始化,这里主要跟平时使用的delay函数有关 可以看到跟main一样,也是创建了一个tidle线程,然后放到就绪态 继续往下,则是系统调度器的初始化 ![image-20240724222207275.png](https://oss-club.rt-thread.org/uploads/20240725/1f518b19745f661bde28fe8f0a736c44.png) 这里主要就是找到高优先级的线程然后把线程就转为运行态 ## Delay函数中的线程调度 当使用rt_thread_mdelay后,就会来到_thread_sleep ![image-20240724222740916.png](https://oss-club.rt-thread.org/uploads/20240725/fd3c36f905cc31795a70a0f187aa0393.png.webp) rt_thread_suspend_with_flag获取线程状态然后将当前的线程挂起,接下来设置开启定时器,然后调度切换其他线程 ## RT-Thread线程实例 接下来尝试开两个线程打印输出count ```c #define THREAD_PRIORITY 25 #define THREAD_STACK_SIZE 512 #define THREAD_TIMESLICE 5 struct tid_param { int id; int ms; }; static struct rt_thread *tid1; static struct rt_thread *tid2; static void thread_entry(void *param) { rt_uint32_t count=0; struct tid_param *tid_p =(struct tid_param *)param; for(count=0;count<10;count++) { rt_kprintf("thread%d %d\n",tid_p->id,count); rt_thread_mdelay(tid_p->ms); } rt_kprintf("thread%d exit\n",tid_p->id); } static int thread_sample(void) { struct tid_param *tid1_param=(struct tid_param*)rt_malloc(sizeof(struct tid_param)); tid1_param->id=1; tid1_param->ms=1000; tid1=rt_thread_create("tid1",thread_entry,(void*)tid1_param,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE); if(tid1!=RT_NULL) { rt_thread_startup(tid1); } struct tid_param *tid2_param=(struct tid_param*)rt_malloc(sizeof(struct tid_param)); tid2_param->id=2; tid2_param->ms=1000; tid2=rt_thread_create("tid2",thread_entry,(void*)tid2_param,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE); if(tid2!=RT_NULL) { rt_thread_startup(tid2); } } MSH_CMD_EXPORT(thread_sample,thread_sample); int main(void) { return 0; } ``` 编译运行看下效果 ![image-20240725004539783.png](https://oss-club.rt-thread.org/uploads/20240725/f4321a4007b5bc38b69203480ff67280.png) 可以看到两个线程交替输出count计数
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
alight
该用户没有签名
文章
8
回答
0
被采纳
0
关注TA
发私信
相关文章
1
[星火一号] 代码模板, 手动写启动代码, 开机后 snprintf 不能处理 %llu 了, 是有什么配置上的冲突吗?
2
使用MDK5.37开发星火一号,双击mklinks.bat 文件后,目录下没有 rt-thread 和 libraries 的文件夹图标。
3
studio文件构建丢失
4
rtt中星火一号stm-32怎么把两个示例工程合并成一个
5
星火一号串口发送问题
6
基于开发板建工程的疑问
7
使用星火一号开发板建工程的奇怪问题
8
星火一号板pwm功能,不报错,但也不输出,为什么?
9
星火一号怎么强制改变已占用的引脚的功能呢
10
火星一号的标准库在哪里?外设的数据手册在哪里看?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部