人们在生活中处理复杂问题时,惯用的方法就是分而治之
,即把一个大问题分解成多个相对简单、比较容易解决的小问题,小问题逐个被解决了,大问题也就随之解决了。一样,在设计一个较为复杂的应用程序时,也一般把一个大型任务分解成多个小任务,而后经过运行这些小任务,最终达到完成大任务的目的。git
在裸机系统中, 系统的主体就是 main 函数里面顺序执行的无限循环,这个无限循环里面 CPU 按照顺序完成各类事情。在多线程系统中,咱们根据功能的不一样,把整个系统分割成一个个独立的且没法返回的函数,这个函数咱们称为线程
。github
RT-Thread 中的线程
由三部分组成:线程代码(函数)、线程控制块、线程堆栈。算法
在一个裸机系统中, 若是有全局变量,有子函数调用,有中断发生。那么系统在运行的时候,全局变量放在哪里,子函数调用时,局部变量放在哪里, 中断发生时,函数返回地址发哪里。编程
若是只是单纯的裸机编程,它们放哪里咱们不用管,可是若是要写一个 RTOS,这些种种环境参数,咱们必须弄清楚他们是如何存储的。数组
在裸机系统中,他们通通放在一个叫栈的地方,栈是单片机 RAM 里面一段连续的内存空间,栈的大小通常在启动文件或者连接脚本里面指定, 最后由 C 库函数_main 进行初始化。微信
可是, 在多线程系统中,每一个线程都是独立的,互不干扰的,因此要为每一个线程都分配独立的栈空间,这个栈空间一般是一个预先定义好的全局数组
, 也能够是动态分配的一段内存空间,但它们都存在于 RAM 中。 如:数据结构
static rt_uint8_t led_stack[512];
线程栈其实就是一个预先定义好的全局数据,数据类型为rt_uint8_t,大小咱们设置为 512。 在 RT-Thread 中,凡是涉及到数据类型的地方, RTThread 都会将标准的 C 数据类型用 typedef 从新取一个类型名, 以“rt”前缀开头。这些通过重定义的数据类型放在 rtdef.h
,如:多线程
在 RT-Thread 中,线程控制块由结构体 struct rt_thread
表示,线程控制块是操做系统用于管理线程的一个数据结构,它会存放线程的一些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之间链接用的链表结构,线程等待事件集合等,详细定义以下(在rtdef.h
中定义):
函数
为led线程定义一个线程控制块:ui
static struct rt_thread led_thread;
线程控制块中的 entry
是线程的入口函数,它是线程实现预期功能的函数。线程的入口函数由用户设
计实现,通常有如下两种代码形式:
在实时系统中,线程一般是被动式的:这个是由实时系统的特性所决定的,实时系统一般老是等待外界事件的发生,然后进行相应的服务:
如简单的顺序语句、 do whlie() 或 for() 循环等,此类线程不会循环或不会永久循环,可谓是 “一次性”线程,必定会被执行完毕。在执行完毕后,线程将被系统自动删除。
咱们的用户线程有两种建立方式,一种是静态线程,另外一种是动态线程。
返回值为错误代码。
返回值为线程控制块 。
一、肯定线程栈
二、定义线程控制块
三、建立线程函数。
#include <rtthread.h> #include <rtdevice.h> #include <board.h> /* 静态线程相关宏定义 */ #define THREAD_PRIORITY 25 /* 优先级 */ #define STACK_SIZE 512 /* 栈大小 */ #define TIMESLICE 5 /* 时间片 */ /* 线程三要素 */ static rt_uint8_t static_thread_stack[STACK_SIZE]; /* 线程栈 */ static struct rt_thread static_thread; /* 线程控制块 */ static void static_thread_entry(void* parameter); /* 线程入口函数 */ /* 静态线程入口函数 */ static void static_thread_entry(void* parameter) { rt_uint32_t i = 0; rt_kprintf("This is static thread!\n"); /* 无限循环*/ while (1) { rt_kprintf("static thread count:%d \r\n", ++i); /* 等待0.5s,让出cpu权限,切换到其余线程 */ rt_thread_delay(500); } } /* 主函数 */ int main(void) { rt_err_t result; /* 建立静态线程 : 优先级 25 ,时间片 5个系统滴答,线程栈512字节 */ result = rt_thread_init(&static_thread, "static_thread", static_thread_entry, RT_NULL, (rt_uint8_t*)&static_thread_stack[0], STACK_SIZE, THREAD_PRIORITY, TIMESLICE); /* 建立成功则启动静态线程 */ if (result == RT_EOK) { rt_thread_startup(&static_thread); } }
运行结果为:
可见,在T-Thread中建立一个线程须要线程栈、线程控制块与线程函数
这三要素。除此以外,须要设置一个线程优先级,由于RT-Thread的调度器是基于优先级的抢占式调度算法。还须要设置一个时间片参数,这个用于多个线程具备同等优先级的状况下,采用时间片的轮转调度算法进行调度,这个值与时间节拍有关,每一秒的节拍数可在rtconfig.h
里进行设置:
在这里咱们只建立一个线程,因此时间片咱们没有用到,但也须要传递一个时间片的值给rt_thread_init
函数。最后,在主函数里调用相关接口建立一个静态线程,建立成功则启动该线程。
建立动态线程与建立静态线程相似:
#include <rtthread.h> #include <rtdevice.h> #include <board.h> /* 动态线程相关宏定义 */ #define THREAD_PRIORITY 25 /* 优先级 */ #define STACK_SIZE 512 /* 栈大小 */ #define TIMESLICE 5 /* 时间片 */ /* 线程三要素 */ static rt_uint8_t dynamic_thread_stack[STACK_SIZE]; /* 线程栈 */ static struct rt_thread dynamic_thread; /* 线程控制块 */ static void dynamic_thread_entry(void* parameter); /* 线程入口函数 */ /* 动态线程入口函数 */ static void dynamic_thread_entry(void* parameter) { rt_uint32_t i; /* 无限循环*/ while (1) { for (i = 0; i < 5; i++) { rt_kprintf("dynamic thread count:%d \r\n", i); /* 等待1s,让出cpu权限,切换到其余线程 */ rt_thread_delay(500); } } } /* 主函数 */ int main(void) { rt_thread_t tid; // 动态线程句柄 /* 建立动态线程 : 优先级 25 ,时间片 5个系统滴答,线程栈512字节 */ tid = rt_thread_create("dynamic_thread", dynamic_thread_entry, RT_NULL, STACK_SIZE, THREAD_PRIORITY, TIMESLICE); /* 建立成功则启动动态线程 */ if (tid != RT_NULL) { rt_thread_startup(tid); } }
运行结果:
上例中,从运行结果上看,是没有任何差异的!那么,咱们在实际中如何抉择?
使用静态线程时,必须先定义静态的线程控制块,而且定义好栈空间,而后调用rt_thread_init()
函数来完成线程的初始化工做。采用这种方式,线程控制块和堆栈占用的内存会放在 RW/ZI
段,这段空间在编译时就已经肯定,它不是能够动态分配的,因此不能被释放,而只能使用 rt_thread_detach()
函数将该线程控制块从对象管理器中脱离。
使用动态定义方式 rt_thread_create()
时, RT-Thread 会动态申请线程控制块和堆栈空间。在编译时,编译器是不会感知到这段空间的,只有在程序运行时, RT-Thread 才会从系统堆中申请分配这段内存空间,当不须要使用该线程时,调用 rt_thread_delete()
函数就会将这段申请的内存空间从新释放到内存堆中。
这两种方式各有利弊,静态定义方式会占用 RW/ZI 空间,可是不须要动态分配内存,运行时效率较高,实时性较好。动态方式不会占用额外的 RW/ZI 空间,占用空间小,可是运行时须要动态分配内存,效率没有静态方式高。
总的来讲,这两种方式就是空间和时间效率的平衡,能够根据实际环境需求选择采用具体的分配方式。就像C编程中,什么时候使用动态空间,什么时候使用静态空间,也须要根据实际状况平衡选择。
个人我的博客:https://zhengnianli.github.io/
个人微信公众号:嵌入式大杂烩