Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RTOS
内核技术
线程运行
操作系统内核技术研究:线程切换与运行
发布于 2021-07-26 19:00:11 浏览:2211
订阅该版
[tocm] [入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) [操作系统内核技术研究:开篇](https://club.rt-thread.org/ask/article/2905.html) [操作系统内核技术研究:环境搭建](https://club.rt-thread.org/ask/article/2906.html) [操作系统内核技术研究:ARM汇编指令](https://club.rt-thread.org/ask/article/2913.html) [操作系统内核技术研究:STMFD与LDMFD的使用](https://club.rt-thread.org/ask/article/2914.html) [操作系统内核技术研究:任务上下文切换](https://club.rt-thread.org/ask/article/2918.html) [操作系统内核技术研究:线程切换与运行](https://club.rt-thread.org/ask/article/2919.html) ## 前言 - RTOS的首要作用,就是线程的切换,就像中断处理流程一样,中断后处理其他的事情,处理完后正常的返回,继续执行。 ## 线程切换 - 这里参考使用RT-Thread现有的内核代码来验证 - 线程切换的主要函数,一般使用汇编语言编写,后续研究每一个函数的具体实现方法。 - 假设我们有了各个线程的处理函数,如何实现相互切换呢? - 这里使用线程栈的管理,实现几个线程间的切换,暂时不实现优先级的调度(切换)逻辑。 - 简单的实现:【想切到哪个线程,就切到哪个线程】 ## 工程搭建 - 需要实现内核栈初始化、线程与调度相关的代码 - `cpuport`部分,我这里使用STM32F103平台 `rt-thread\libcpu\arm\cortex-m3`目录,拷贝到自己的测试工程里,并手动加入Keil MDK5工程。 - 注释掉:`context_rvds.S`中的:`rt_hw_hard_fault_exception`的实现,暂时不使用:HardFault_Handler的重写。 - 以下几个内核文件,先保证功能正常编译即可,不需要全部COPY过来。 ### 类型与数据结构的定义:`rtdef.h` ```c /* rtdef.h 类型、数据结构定义 */ #ifndef __RTDEF_H__ #define __RTDEF_H__ typedef signed char rt_int8_t; typedef signed short rt_int16_t; typedef signed int rt_int32_t; typedef unsigned char rt_uint8_t; typedef unsigned short rt_uint16_t; typedef unsigned int rt_uint32_t; typedef int rt_bool_t; typedef long rt_base_t; typedef unsigned long rt_ubase_t; typedef rt_base_t rt_err_t; typedef rt_uint32_t rt_tick_t; #define RT_TRUE 1 #define RT_FALSE 0 #define RT_EOK 0 #define RT_ERROR 1 #define ALIGN(n) __attribute__((aligned(n))) #define RT_ALIGN(size, align) (((size) + (align) - 1) & ~ ((align) - 1)) #define RT_ALIGN_DOWN(size, align) ((size) & ~ ((align) - 1)) #define RT_NULL (0) struct rt_thread { /* stack point and entry */ void *sp; void *entry; void *parameter; void *stack_addr; rt_uint32_t stack_size; }; #endif ``` ### rthw.h - 硬件移植相关的接口 开关中断 栈初始化等 ,此部分接口,主要来自移植文件,如:`context_rvds.S` 汇编文件中实现。 ```c /* rthw.h 硬件移植相关的接口 开关中断 栈初始化等 */ #ifndef __RT_HW_H__ #define __RT_HW_H__ #include
rt_base_t rt_hw_interrupt_disable(void); void rt_hw_interrupt_enable(rt_base_t level); void rt_hw_context_switch_to(rt_uint32_t to); void rt_hw_context_switch(rt_uint32_t from, rt_uint32_t to); rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit); #endif ``` ### rtthread.h文件 - 主头文件,这里只需要实现其他头文件的包含,线程初始化与调度的接口。 ```c /* rtthread.h 主头文件 */ #ifndef __RTTHREAD_H__ #define __RTTHREAD_H__ #include
#include
#include
#include
void rt_system_scheduler_start(struct rt_thread *to_thread); void rt_thread_init(struct rt_thread *thread, void (*entry)(void *param), void *param, void *stack_start, rt_uint32_t stack_size); #endif ``` ### thread.c - 功能实现:线程初始化 ```c /* thread.c 线程相关的函数实现 如初始化 */ #include
void rt_thread_init(struct rt_thread *thread, void (*entry)(void *param), void *param, void *stack_start, rt_uint32_t stack_size) { thread->entry = (void *)entry; thread->parameter = param; thread->stack_addr = stack_start; thread->stack_size = stack_size; memset(thread->stack_addr, '#', thread->stack_size); thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter, (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_uint32_t)), RT_NULL); } ``` ### 调度器:scheduler.c - 这里只实现初步的启用线程。 ```c /* scheduler.c 调度,这里先实现手动调度 */ #include
void rt_system_scheduler_start(struct rt_thread *to_thread) { rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp); } ``` ## 用户测试程序 - `task_test.c`,主要用于测试线程的定义与初始化,线程切换逻辑实现 ```c /* task_test.c */ #include
#include
#include
#include
//#include "printk.h" #include "task_test.h" #define TASK1_STACK_SIZE 1024 #define TASK2_STACK_SIZE 1024 #define TASK3_STACK_SIZE 1024 #define TASK4_STACK_SIZE 1024 ALIGN(RT_ALIGN_SIZE) struct rt_thread t4; struct rt_thread t3; struct rt_thread t2; struct rt_thread t1; static uint8_t task4_stack[TASK3_STACK_SIZE]; static uint8_t task3_stack[TASK3_STACK_SIZE]; static uint8_t task2_stack[TASK2_STACK_SIZE]; static uint8_t task1_stack[TASK1_STACK_SIZE]; void task1_entry(void *param) { rt_ubase_t level; static rt_ubase_t cnt = 0x00; while (1) { //printk("task1 run.\r\n"); HAL_Delay(3000); level = rt_hw_interrupt_disable(); cnt++; rt_hw_interrupt_enable(level); if (cnt >= 3) { cnt = 0; //printk("1->2\r\n"); task1_to_task2(); } } } void task2_entry(void *param) { rt_ubase_t level; static rt_ubase_t cnt = 0x00; while (1) { //printk("task2 run.\r\n"); HAL_Delay(3000); level = rt_hw_interrupt_disable(); cnt++; rt_hw_interrupt_enable(level); if (cnt >= 3) { cnt = 0; //printk("2->3\r\n"); task2_to_task3(); } } } void task3_entry(void *param) { rt_ubase_t level; static rt_ubase_t cnt = 0x00; while (1) { //printk("task3 run.\r\n"); HAL_Delay(3000); level = rt_hw_interrupt_disable(); cnt++; rt_hw_interrupt_enable(level); if (cnt >= 3) { cnt = 0; //printk("3->1\r\n"); task3_to_task1(); } } } void task4_entry(void *param) { rt_ubase_t level; static rt_ubase_t cnt = 0x00; while (1) { //printk("task4 run.\r\n"); HAL_Delay(3000); level = rt_hw_interrupt_disable(); cnt++; rt_hw_interrupt_enable(level); if (cnt >= 3) { cnt = 0; //printk("4->1\r\n"); task4_to_task1(); } } } void task1_init(void) { rt_thread_init(&t1, task1_entry, RT_NULL, task1_stack, TASK1_STACK_SIZE); } void task2_init(void) { rt_thread_init(&t2, task2_entry, RT_NULL, task2_stack, TASK2_STACK_SIZE); } void task3_init(void) { rt_thread_init(&t3, task3_entry, RT_NULL, task3_stack, TASK3_STACK_SIZE); } void task4_init(void) { rt_thread_init(&t4, task4_entry, RT_NULL, task4_stack, TASK4_STACK_SIZE); } void task1_run(void) { rt_system_scheduler_start(&t1); } void task2_run(void) { rt_system_scheduler_start(&t2); } void task3_run(void) { rt_system_scheduler_start(&t3); } void task4_run(void) { rt_system_scheduler_start(&t4); } void task1_to_task2(void) { rt_hw_context_switch((rt_ubase_t)&t1.sp, (rt_ubase_t)&t2.sp); } void task2_to_task3(void) { rt_hw_context_switch((rt_ubase_t)&t2.sp, (rt_ubase_t)&t3.sp); } void task3_to_task1(void) { rt_hw_context_switch((rt_ubase_t)&t3.sp, (rt_ubase_t)&t1.sp); } void task4_to_task1(void) { rt_hw_context_switch((rt_ubase_t)&t4.sp, (rt_ubase_t)&t1.sp); } ``` ### task_test.h ```c /* task_test.h */ #ifndef __TASK_TEST_H__ #define __TASK_TEST_H__ void task1_init(void); void task2_init(void); void task3_init(void); void task4_init(void); void task1_run(void); void task2_run(void); void task3_run(void); void task4_run(void); void task1_to_task2(void); void task2_to_task3(void); void task3_to_task1(void); void task4_to_task1(void); #endif ``` ## main ```c #include
#include
#include "test.h" #include "task_test.h" /** * @brief The application entry point. * @retval int */ int main(void) { hw_board_init(); //stmfd_test(); /* 线程初始化 */ task1_init(); task2_init(); task3_init(); task4_init(); task1_run(); /* 运行第一个线程 */ task1_to_task2(); /* 切换线程 task1->task2*/ while (1) { HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_RESET); HAL_Delay(1000); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET); HAL_Delay(1000); } } ``` ## 编译下载与调试: - 注释掉不相干的代码,设置好路径,应该可以正常的编译、下载。 - 软件调试一下:发现线程可以正常的初始化、线程可以启动(不再继续执行main 的 while(1)) - 验证各个线程,可以灵活的手动切换并运行。 ### 运行task1 ![2021-07-20_080827.png](https://oss-club.rt-thread.org/uploads/20210726/769672698449a5a62729c55cef0f41b0.png.webp) ### 切换task2并运行 ![2021-07-20_080855.png](https://oss-club.rt-thread.org/uploads/20210726/20ab85d14afc3cca297fa57234559ba0.png.webp) ## 小结 - 初步的切换思路已经清楚,对线程切换,不再那么的神秘,有了调试基础 - 继续深入线程的切换(任务上下文切换) - 了解调度器,如优先级调度,用于线程切换逻辑实现,如何自动切换运行各个线程。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
809
被采纳
175
关注TA
发私信
相关文章
1
RTOS情况下,串口字节丢失
2
RTT的休眠模式怎么样
3
物联网操作系统有哪些
4
新手小白,关于RTOS选择的疑问
5
用rt在stmf103里面产生pwm(400KHZ),大佬们是怎么做的?
6
Linux开发和RTOS开发的区别?
7
rttread os 对于引脚复用的配置
8
发生hard fault on handler怎么定位什么问题?
9
HC32F030F8TA移植RT_Thread在创建任务完成进入任务调度中出错跑飞怎么处理?
10
用mountriver创建rtt工程,整数ok,开浮点一到rt_thread_mdelay就挂了
推荐文章
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
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部