本文参考自[野火EmbedFire]《RT-Thread内核实现与应用开发实战——基于STM32》,仅作为个人学习笔记。更详细的内容和步骤请查看原文(可到野火资料下载中心下载)
动态内存空间
上一节静态线程的线程空间为一个静态数组,每个静态线程的空间都需要提前定义好大小。而动态线程的使用的栈和线程控制块是在创建线程的时候 RT-Thread 动态分配的,并不是预先定义好的全局变量。
那么线程的动态空间从哪里来呢?
RT-Thread 在 SRAM 里面定义一个大数组供系统的动态内存分配函数使用,这些代码在 board.c
开头实现,内容如下:
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
/*
* Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP
* the RT_HEAP_SIZE max value = (sram size - ZI size), 2048 means 2048*4 bytes
*/
#define RT_HEAP_SIZE 2048
static uint32_t rt_heap[RT_HEAP_SIZE];
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
/**
* This function will initial your board.
*/
void rt_hw_board_init(void)
{
/* ...省略部分代码 */
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
上面三个函数的功能分别是获取堆的起始地址,获取堆的结束地址以及初始化系统堆空间。要使能动态堆,还需要在rtconfig.h
进行配置,
定义线程控制块指针
rt_thread_t
是线程控制块结构体rt_thread
的指针类型,动态线程需要通过线程创建函数来获取线程控制块。
// 定义线程控制块指针
static rt_thread_t led0_thread = RT_NULL;
定义线程函数
线程函数即线程入口函数,是线程的功能代码,由于线程需要不停运行,所以需要加上一个while(1)
,下面这个线程函数实现的功能是LED0以500ms的间隔进行闪烁。
/******************************************************************************
* @ 函数名 : led0_thread_entry
* @ 功 能 : LED0线程入口函数
* @ 参 数 : parameter 外部传入的参数
* @ 返回值 : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
while(1)
{
LED0(ON);
rt_thread_delay(500); // 500个tick(500ms)
LED0(OFF);
rt_thread_delay(500);
}
}
创建线程
与静态线程的rt_thread_init()
不同的是,动态线程使用rt_thread_create()
函数来创建一个线程,两者的函数名不一样,具体的形参也有区别。
// 创建一个动态线程
led0_thread = // 线程控制块指针
rt_thread_create("led0", // 线程名字
led0_thread_entry, // 线程入口函数
RT_NULL, // 入口函数参数
255, // 线程栈大小
5, // 线程优先级
10); // 线程时间片
关于线程的优先级,一定要填rtconfig.h
中规定的范围内的数字(在移植系统时,我把线程优先级的最大值设置成了8),如果线程初始化时将优先级设置过大,线程将不会工作。
启动线程
线程初始化后,线程只是处于初始态(RT_THREAD_INIT),要想让线程进入就绪态(RT_THREAD_READY),还需使用rt_thread_startup()
函数。由于线程控制块指针是动态获取的,调度线程前,有必要先确认动态线程是否创建成功。
// 开启线程调度
if(led0_thread != RT_NULL)
rt_thread_startup(led0_thread);
else
return -1;
实验效果
完整代码
所有动态线程相关函数我都放在main.c,下面代码不包括底层驱动代码(比如LED初始化)。
#include "board.h"
#include "rtthread.h"
// 定义线程控制块指针
static rt_thread_t led0_thread = RT_NULL;
/******************************************************************************
* @ 函数名 : led0_thread_entry
* @ 功 能 : LED0线程入口函数
* @ 参 数 : parameter 外部传入的参数
* @ 返回值 : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
while(1)
{
LED0(ON);
rt_thread_delay(500); // 500个tick(500ms)
LED0(OFF);
rt_thread_delay(500);
}
}
int main(void)
{
// 硬件初始化和RTT的初始化已经在component.c中的rtthread_startup()完成
// 创建一个动态线程
led0_thread = // 线程控制块指针
rt_thread_create("led0", // 线程名字
led0_thread_entry, // 线程入口函数
RT_NULL, // 入口函数参数
255, // 线程栈大小
5, // 线程优先级
10); // 线程时间片
// 开启线程调度
if(led0_thread != RT_NULL)
rt_thread_startup(led0_thread);
else
return -1;
}