RTThread学习笔记——对于线程的个人了解(二)
线程与线程就绪列表:
在RTT系统中,链表是一个相当重要的数据结构,RTT通过链表,来管理一些事物,例如说线程。
在线程控制块中,有一个线程链表节点:
rt_list_t tlist; /**< the thread list */
这个节点可以将线程控制块挂载到一些链表中。在线程创建之后,线程首先被添加到就绪列表中,就绪列表也被叫做线程优先级表。
就绪列表实际上是一个 rt_list_t 的数组。rt_list_t 是一个RTT定义的双向链表类型,也就是说,这个数组的每个元素都是一个双向链表。
/*就绪列表数组定义,在scheduler.c中*/ rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; /*RT_THREAD_PRIORITY_MAX定义,在rtconfig.h中*/ /*这里定义为32,决定了线程的优先级有多少个,这是RTT的优点之一*/ #define RT_THREAD_PRIORITY_MAX 32
这里我们得知,数组的下标对应了线程的优先级,在RTT系统中,优先级数字越小,逻辑优先级越高。
在实际运行流程中,RTT通过rt_thread_startup来将线程插入到就绪列表/线程优先级表中。
线程调度:
现在,我们拥有了线程优先级表,接下来要实现的就是线程调度。
线程调度通过调度器来完成,调度器是RTOS系统的核心。
在调度器之前,先来看下RTT系统为了调度所设立的一个数——线程优先级组。
#if RT_THREAD_PRIORITY_MAX > 32 /* Maximum priority level, 256 */ rt_uint32_t rt_thread_ready_priority_group; rt_uint8_t rt_thread_ready_table[32]; #else /* Maximum priority level, 32 */ rt_uint32_t rt_thread_ready_priority_group; #endif
在这里,我们使用的MAX数小于等于32,所以使用的是else之后的定义。
线程优先级组是来做什么的?这里举一个荔枝:线程3准备好了,这时,优先级组的第3位就会置1,然后线程会被插入优先级表组(就绪列表)的第3个链表中。
然后在下一个系统周期中,调度器会从优先级组中发现优先级最高且置1的位,并且根据这个位从相应的优先级表中读取线程控制块,并跳转到这个线程上。具体识别位置并进行跳转的机制是通过一个已经定义的数组实现,在kservice.c中定义,这里不详细讨论。
线程的状态与需要编程事项:
RTT系统中的每个线程都有多种运行的状态:
初始态:刚创建时的线程状态
就绪态:线程在就绪列表中/优先级表中,等待调度运行
运行态:顾名思义,正在运行的线程
挂起态:正在运行的线程被挂起,被阻塞延时,等待信号时的状态,此时线程不在就绪列表中
关闭态:线程结束
需注意什么?
首先,在线程中,是不允许出现不让出CPU的死循环的,线程必须在非活跃状态下进入挂起或者阻塞,即使是优先级非常高的线程,也必须让出一定时间,或者在一段时间后结束,否则RTOS系统就失去了意义。
其次,无论是哪种方式编程,中断都应该尽量要短,一般只是进行标记,太长的中断有时对系统会产生巨大的不利影响。
最后,既然RTOS,就要考虑其实时性,这里的实时是一个相对的指标,各个线程的实时响应时间都应符合具体的要求(例如响应时间小于5ms)。

浙公网安备 33010602011771号