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)。

 

posted @ 2020-08-13 14:34  阿韬  阅读(1012)  评论(0)    收藏  举报