RT-Thread之线程实现就绪列表

时间:2021-07-01 16:21:18   收藏:0   阅读:0

1、定义就绪列表

线程创建好之后,我们需要把线程添加到就绪列表里面,表示线程已经就绪,系统随时可以调度。就绪列表在schedule.c中定义。

/* 线程就绪列表 */
 rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; 

就绪列表实际上就是一个rt_list_t 类型的数组,数组的大小由决定最大线程优先级的宏RT_THREAD_PRIORITY_MAX决定,RT_THREAD_PRIORITY_MAX在rtconfig中默认定义为32.数组的下标对应了线程的优先级,同一优先级的线程统一插入到就绪列表的同一链表中。一个空的就绪列表如下:

技术图片

 

 2、将线程插入到就绪列表

线程控制块里面有一个tlist成员,数据类型为rt_list_t,我们将线程插入到就绪列表里面,就是通过将线程控制块的tlist这个节点插入到就绪列表中来实现的。如果把就绪列表比作晾衣杆,线程就是衣服,那tlist就是晾衣架,就是为了把自己挂在各种不同的链表中。线程插入到就绪列表的示意图。

技术图片

 

 3、实现调度器

调度器是操作系统的核心,其主要功能就是实现线程的切换,即从就绪列表里面找到优先级最高的的线程,然后去执行该线程。从代码上来看,调度器无非也就是由几个全局变量和一些可以实现线程切换的函数组成,全部都在schedule.c文件中实现。

3.1调度器初始化

调度器在使用之前必须先初始化,具体如下:

/* 初始化系统调度器 */
void rt_system_scheduler_init(void)
{ 
    register rt_base_t offset;// (1)
/* 线程就绪列表初始化 */
     for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)                // (2)
     {
         rt_list_init(&rt_thread_priority_table[offset]);  //(2)
     }

 /* 初始化当前线程控制块指针 */
     rt_current_thread = RT_NULL;// (3)

 }

 

(1) :定义一个局部变量,用 C 语言关键词 register 修饰,防止被编译器优化。
(2) :初始化线程就绪列表,初始化完后,整个就绪列表为空,具体见图:空的线程就绪列表。
技术图片

 

 

(3) :初始化当前线程控制块指针为空。rt_current_thread 是在 scheduler.c 中定义的一个 struct rt_thread 类型的全局指针,用于指向当前正在运行的线程的线程
控制块。
  我们把调度器初始化一般放在硬件初始化之后,线程创建之前

3、启动调度器

调度器启动由函数 rt_system_scheduler_start() 来完成。调度器在启动的时候会从就绪列表中取出优先级最高的线程的线程控制块,然后切换到该线程。、

4、第一次线程切换

rt_hw_context_switch_to() 函数,第一次切换到新的线程,该函数在 context_rvds.s 中实现,在 rthw.h 声明,用于实现第一次线程切换。当一个汇编函数在 C 文件中调用的时候,如果有一个形参,则执行的时候会将这个形参传入到 CPU 寄存器 r0,如果有两个形参,第二个则传入到 r1。rt_hw_context_switch_to() 的具体实现见代码清单: 线程的定义-26。context_rvds.s 文件中涉及到的 ARM 汇编指令具体参考ARM 常用汇编指令讲解。
技术图片

 

 技术图片

 5、系统调度

系统调度就是在就绪列表中寻找优先级最高的就绪线程,然后去执行该线程。系统调度函数rt_schedule()。

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!