《野火RT-Thread内核实现与应用开发实战》笔记5. 支持多优先级

本文详细介绍了实时操作系统(RTOS)中线程就绪优先级组的概念,它通过32位整数表示线程优先级,当优先级超过32时使用数组扩展。快速查找最高优先级的方法通过预计算的索引表实现。线程优先级列表是一个双向链表数组,用于按优先级组织线程。线程初始化和启动涉及设置优先级、状态和插入就绪列表。系统调度过程中,通过查找最高优先级线程并进行切换来保证执行效率。
摘要由CSDN通过智能技术生成
1. 线程就绪优先级组
  1. 简介

    线程就绪优先级组定义如下:

    rt_uint32_t rt_thread_ready_priority_group;
    

    从代码上看,线程就绪优先级组就是一个 32 位的整形数, 每一个位对应一个优先级。一个就绪优先级组最多只能表示 32 个优先级,如果优先级超过 32 个怎么办,则可以定义一个线程就绪优先级数组, 每一个数组成员都可以表示 32 个优先级,具体支持到少由系统的 RAM 的大小决定。

    线程就绪优先级组的每一个位对应一个优先级,位 0 对应优先级 0,位 1 对应优先级 1,以此类推。比如,当优先级为 10 的线程已经准备好,那么就将线程就绪优先级组的位 10 置 1,表示线程已经就绪,然后根据 10 这个索引值,在线程优先级表 10(rt_thread_priority_table[10]) 的这个位置插入线程。 有关线程就绪优先级组的位号与线程优先级对应的关系如下图所示:
    在这里插入图片描述

  2. 快速查找最高优先级的方法

    /**
     * 将 8 位整形数的取值范围 0~255 作为数组__lowest_bit_bitmap[]的索引,
     * 索引值第一个出现 1(从最低位开始)的位号作为该数组索引下的成员值
     */
    const rt_uint8_t __lowest_bit_bitmap[] = {
        0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
    };
    
    /**
     * 该函数用于从一个32位的数中寻找第一个被置1的位(从低位开始),
     * 然后返回该位的索引(即位号)
     *
     * \return 返回第一个置1位的索引号。如果全为0,则返回0。
     */
    int __rt_ffs (int value)
    {
        /* 如果值为0,则直接返回0 */
        if (value == 0) return 0;
        
        /* 
         * 检查bits[07:00]
         * 这里加1的原因是避免当第一个置1的位是位0时,返回的索引号与值都为0时返回的
         * 索引号重复
         */
        if (value & 0xFF)
            return __lowest_bit_bitmap[value & 0xFF] + 1;
        
        /* 检查bits[15:08] */
        if (value & 0xFF00)
            return __lowest_bit_bitmap[(value & 0xFF00) >> 8] + 9;
        
        /* 检查bits[23:16] */
        if (value & 0xFF0000)
            return __lowest_bit_bitmap[(value & 0xFF0000) >> 16] + 17;
        
        /* 检查bits[31:24] */
        if (value & 0xFF000000)
            return __lowest_bit_bitmap[(value & 0xFF000000) >> 24] + 25;
    }
    
2. 线程优先级列表

线程优先级表定义如下:

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

线程优先级表的数据类型为 rt_list,每个索引号对应线程的优先级,该索引下维护着一条双向链表,当线程就绪时,线程就会根据优先级插入到对应索引的链表, 同一个优先级的线程都会被插入到同一条链表中(当同一个优先级下有多个线程时,需要时间片的支持,后面的章节再讲解) 。 一个有 5 个线程就绪的就绪列表示意图如下图所示,其中thread1和thread4为同一优先级。
在这里插入图片描述

3. 线程初始化过程
rt_err_t rt_thread_init rt_thread_init (struct rt_thread *thread,  /* 线程控制块 */
                						const char       *name,    /* 线程名字,字符串形式 */
                    					void (*entry) (void *parameter), /* 线程入口地址 */
                    					void             *parameter,    /* 线程形参 */
                   						void             *stack_start,  /* 线程栈起始地址 */
                    					rt_uint32_t 	  stack_size,	/* 线程栈大小 */
                    					rt_uint8_t        priority)		/* 线程优先级 */
{
	// 1. 线程对象初始化,并添加到对象容器中
    // 2. 初始化线程控制块成员(链表节点、入口地址、形参、栈地址、栈大小、栈指针)
    // 3. 初始化线程优先级(初始优先级、当前优先级、当前优先级掩码)
    // 4. 初始化线程错误码和状态
}

rt_err_t rt_thread_startup (rt_thread_t thread)
{
    // 1. 设置线程优先级(当前优先级、当前优先级掩码)
    // 2. 设置线程状态为挂起状态(SUSPEND)
    // 3. 将线程插入到就绪列表
    //  3.1. 设置线程状态为就绪状态(READY)
    //  3.2. 将线程插入到线程优先级列表末尾
    //  3.3. 设置线程就绪优先级组中对应的位为1
    // 4. 如果当前线程不为RT_NULL,则执行系统调度
}
4. 系统调度过程
void rt_schedule (void)
{   
    // 1. 获取就绪的最高优先级 
  	// 2. 获取最高优先级线程(目标线程)对应的线程控制块
    // 3. 如果目标不是当前线程,则执行线程切换
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值