前言
RT-thread自学笔记记录,2022年底听说RT-Thread,2024年初开始看,4月份开始比较正经的学,用这个笔记梳理一下学习的思路,也激发一下自己的动力。
这份笔记主要是参考野火的《RT-Thread内核实现与应用开发实战指南》、韦东山的视频课、正点原子潘多拉的教程。
初学记录,逐步理解,加油加油!
一、单线程线程静态内存与动态内存的区别
1、理解区别
静态内存: 线程使用的栈和线程控制块都使用静态内存,即预先定义好的全局变量,这些预先定义好的全局变量都存在内部的 SRAM 中。线程控制块和线程栈的内存空间都是从内部的 SRAM 里面分配的,具体分配到哪个地址由编译器决定。
动态内存: 线程使用的栈和线程控制块是在创建线程的时候 RT-Thread 动态分配的,并不是预先定义好的全局变量。动态内存,即堆,其实堆也是内存,也属于 SRAM。现在我们的做法是在 SRAM 里面定义一个大数组供 RT-Thread 的动态内存分配函数使用,这些代码在 board.c 开头实现。
使用选择: 当前这个例程,线程的栈,线程的控制块用的都是静态内存,必须由用户预先定义,这种方法我们在使用 RT-Thread 的时候用的比较少,通常的方法是在线程创建的时候动态的分配线程栈和线程控制块的内存空间,
2、单线程静态内存
此处列出静态的目的是对比两者区别:线程的栈,线程的控制块用的都是静态内存,必须由用户预先定义,这种方法我们在使用 RT-Thread 的时候用的比较少,通常的方法是在线程创建的时候动态的分配线程栈和线程控制块的内存空间。
1、操作流程:
①定义线程函数(main.c)
线程实际上就是一个无限循环且不带返回值的 C 函数。
/*线程定义*/
static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时500个tick */
LED1_OFF;
rt_thread_delay(500); /* 延时500个tick */
}
}
②定义线程栈(main.c)
线程的栈占用的是 MCU 内部的 RAM,当线程越多的时候,需要使用的栈空间就越大,即需要使用的RAM 空间就越多。一个 MCU 能够支持多少线程,就得看你的 RAM 空间有多少。
ALIGN 是在 rtdef.h 里面定义的一个宏。
ALIGN 宏的形参 RT_ALIGB_SIZE 是在 rtconfig.h 中的一个宏,目前定义为 4。
/* 定义线程控栈时要求RT_ALIGN_SIZE个字节对齐 */
ALIGN(RT_ALIGN_SIZE)
/* 定义线程栈 */
static rt_uint8_t rt_led1_thread_stack[1024];
③定义线程控制块(main.c)
线程控制块就是一个结构体。
/* 定义线程控制块 */
static struct rt_thread led1_thread;
④初始化线程(main.c)
线程的三要素是线程主体函数,线程栈,线程控制块,通过线程初始化函数 rt_thread_init(),将线程主体函数,线程栈(静态的)和线程控制块(静态的)这三者联系在一起。
rt_thread_init(&led1_thread, /* 线程控制块 */
"led1", /* 线程名字 */
led1_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
&rt_led1_thread_stack[0], /* 线程栈起始地址 */
sizeof(rt_led1_thread_stack), /* 线程栈大小 */
3, /* 线程的优先级 */
20); /* 线程时间片 */
}
⑤启动线程
/* 启动线程,开启调度 */
rt_thread_startup(&led1_thread);
2、main.c整体代码
/*包含的头文件*/
#include "board.h"
#include "rtthread.h"
/*变量*/
/* 定义线程控制块 */
static struct rt_thread led1_thread;
/* 定义线程控栈时要求RT_ALIGN_SIZE个字节对齐 */
ALIGN(RT_ALIGN_SIZE)
/* 定义线程栈 */
static rt_uint8_t rt_led1_thread_stack[1024];
/* 函数声明*/
static void led1_thread_entry(void* parameter);
/* main 函数*/
int main(void)
{
/*
* 开发板硬件初始化,RTT系统初始化已经在main函数之前完成,
* 即在component.c文件中的rtthread_startup()函数中完成了。
* 所以在main函数中,只需要创建线程和启动线程即可。
*/
rt_thread_init(&led1_thread, /* 线程控制块 */
"led1", /* 线程名字 */
led1_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
&rt_led1_thread_stack[0], /* 线程栈起始地址 */
sizeof(rt_led1_thread_stack), /* 线程栈大小 */
3, /* 线程的优先级 */
20); /* 线程时间片 */
rt_thread_startup(&led1_thread); /* 启动线程,开启调度 */
}
/*线程定义*/
static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时500个tick */
LED1_OFF;
rt_thread_delay(500); /* 延时500个tick */
}
}
/********************************END OF FILE****************************/
3、单线程动态内存
在创建单线程—SRAM 静态内存的例程中,线程控制块和线程栈的内存空间都是从内部的 SRAM 里面分配的,具体分配到哪个地址由编译器决定。现在我们开始使用动态内存,即堆,其实堆也是内存,也属于 SRAM。现在我们的做法是在 SRAM 里面定义一个大数组供 RT-Thread 的动态内存分配函数使用,这些代码在 board.c 开头实现。
1、操作流程
动态内存空间的堆从哪里来?
已看懂代码,但不理解使用,后面再补充。
/*代码参考野火117页*/
①定义线程函数
使用动态内存的时候,线程的主体函数与使用静态内存时是一样。
/*线程定义*/
static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时500个tick */
LED1_OFF;
rt_thread_delay(500); /* 延时500个tick */
}
}
②定义线程栈
使用动态内存的时候,线程栈在线程创建的时候创建,不用跟使用静态内存那样要预先定义好一个全局的静态的栈空间。
③定义线程控制块指针
使用动态内存时候,不用跟使用静态内存那样要预先定义好一个全局的静态的线程控制块空间。线程控制块是在线程创建的时候创建,线程创建函数会返回一个指针,用于指向线程控制块,所以要预先为线程栈定义一个线程控制块指针。
/* 定义线程控制块指针 */
static rt_thread_t led1_thread = RT_NULL;
④创建线程
使用静态内存时,使用 rt_thread_init()来初始化一个线程,使用动态内存的时,使用rt_thread_create()函数来创建一个线程,两者的函数名不一样,具体的形参也有区别。
led1_thread = /* 线程控制块指针 */
rt_thread_create( "led1", /* 线程名字 */
led1_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
512, /* 线程栈大小 */
3, /* 线程的优先级 */
20); /* 线程时间片 */
}
⑤启动线程
当线程创建好后,是处于线程初始态(RT_THREAD_INIT),并不能够参与操作系统的调度,只有当线程进入就绪态(RT_THREAD_READY)之后才能参与操作系统的调度。线程由初始态进入就绪态可由函数 rt_thread_startup()来实现。
/* 启动线程,开启调度 */
if (led1_thread != RT_NULL)
rt_thread_startup(led1_thread);
else
return -1;
2、main.c整体代码
/*包含的头文件*/
#include "board.h"
#include "rtthread.h"
/*变量*/
/* 定义线程控制块 */
static rt_thread_t led1_thread = RT_NULL;
/* 函数声明*/
static void led1_thread_entry(void* parameter);
/* main 函数*/
int main(void)
{
/*
* 开发板硬件初始化,RTT系统初始化已经在main函数之前完成,
* 即在component.c文件中的rtthread_startup()函数中完成了。
* 所以在main函数中,只需要创建线程和启动线程即可。
*/
led1_thread = /* 线程控制块指针 */
rt_thread_create( "led1", /* 线程名字 */
led1_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
512, /* 线程栈大小 */
3, /* 线程的优先级 */
20); /* 线程时间片 */
/* 启动线程,开启调度 */
if (led1_thread != RT_NULL)
rt_thread_startup(led1_thread);
else
return -1;
}
/*线程定义*/
static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时500个tick */
LED1_OFF;
rt_thread_delay(500); /* 延时500个tick */
}
}
/********************************END OF FILE****************************/
二、多线程静态内存和动态内存的区别
1.多线程区别
2.多线程与单线程下动态和静态的区别
总结
提示:持续更新中。。。