rtthread优先级的实现

31 篇文章 4 订阅

title: rtthread优先级的实现
date: 2020-10-22 17:42:59
tags: rtthread


就绪列表

RT-Thread 要支持多优先级,需要靠就绪列表的支持,从代码上看,就绪列表由两个在 scheduler.c 文件定义的全局变量组成,一个是线程就绪优先级组rt_thread_ready_priority_group,另一个是线程优先级表rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]

将线程插入到线程优先级表,如图:

charj.png

线程就绪优先级组

为了快速的找到线程在线程优先级表的插入和移除的位置,RT-Thread 专门设计了一个线程就绪优先级组。从代码上看,线程就绪优先级组就是一个 32 位的整形数,每一个位对应一个优先级。一个就绪优先级组最多只能表示 32 个优先级,如果优先级超过 32 个怎么办,则可以定义一个线程就绪优先级数组,每一个数组成员都可以表示 32 个优先级,具体支持到少由系统的 RAM 的大小决定

scheduler.c

/* 线程就绪优先级组 */
rt_uint32_t rt_thread_ready_priority_group;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fS3chdJc-1608216177477)(https://i.loli.net/2020/10/22/pVOcLNnfqJt2mPB.png)]

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

寻找最高优先级的线程

RT-Thread kservice.c 文件中,有一个专门的函数__rt_ffs,用来寻找 32 位整形数第一个(从低位开始)置 1 的位号。

/**
 * 该函数用于从一个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] */
    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}
/* 
 * __lowest_bit_bitmap[] 数组的解析
 * 将一个8位整形数的取值范围0~255作为数组的索引,索引值第一个出现1(从最低位开始)的位号作为该数组索引下的成员值。
 * 举例:十进制数10的二进制为:0000 1010,从最低位开始,第一个出现1的位号为bit1,则有__lowest_bit_bitmap[10]=1
 * 注意:只需要找到第一个出现1的位号即可
 */
const rt_uint8_t __lowest_bit_bitmap[] =
{
    /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

线程优先级表

线程优先级表是一个在 scheduler.c 中定义的全局数组

/* 线程优先级表 */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

一个空的线程优先级表,如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KHXa4O7v-1608216177479)(https://i.loli.net/2020/10/22/Yl8zXrF5iAx7kqL.png)]

有 5 个线程就绪的就绪列表(其中优先级 1 下有两个线程),如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KfE9tLiV-1608216177481)(https://i.loli.net/2020/10/22/aVfjk2scBvoKYXE.png)]

线程插入与删除

void rt_schedule_insert_thread(struct rt_thread *thread)
{
    register rt_base_t temp;

    /* 关中断 */
    temp = rt_hw_interrupt_disable();

    /* 改变线程状态 */
    thread->stat = RT_THREAD_READY;

    /* 将线程插入就绪列表 */
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                          &(thread->tlist));

    /* 设置线程就绪优先级组中对应的位 */
    rt_thread_ready_priority_group |= thread->number_mask;

    /* 开中断 */
    rt_hw_interrupt_enable(temp);
}


void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t temp;


    /* 关中断 */
    temp = rt_hw_interrupt_disable();
    
    /* 将线程从就绪列表删除 */
    rt_list_remove(&(thread->tlist));
    
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
    {
        rt_thread_ready_priority_group &= ~thread->number_mask;
    }

    /* 开中断 */
    rt_hw_interrupt_enable(temp);
}

支持多优先级

线程控制块

线程控制块与优先级相关的成员

/*
*************************************************************************
*                               线程结构体
*************************************************************************
*/
struct rt_thread
{
    /* rt 对象 */
    char        name[RT_NAME_MAX];    /* 对象的名字 */
    rt_uint8_t  type;                 /* 对象类型 */
    rt_uint8_t  flags;                /* 对象的状态 */
    rt_list_t   list;                 /* 对象的列表节点 */
    
	rt_list_t   tlist;                /* 线程链表节点 */
    
	void        *sp;	              /* 线程栈指针 */
	void        *entry;	              /* 线程入口地址 */
	void        *parameter;	          /* 线程形参 */	
	void        *stack_addr;          /* 线程起始地址 */
	rt_uint32_t stack_size;           /* 线程栈大小,单位为字节 */
	
    rt_ubase_t  remaining_tick;       /* 用于实现阻塞延时 */
    
    rt_uint8_t  current_priority;     /* 当前优先级 */
    rt_uint8_t  init_priority;        /* 初始优先级 */
    rt_uint32_t number_mask;          /* 当前优先级掩码 */
    
    rt_err_t    error;                /* 错误码 */
    
    rt_uint8_t  stat;                 /* 线程的状态 */
};
typedef struct rt_thread *rt_thread_t;

错误码定义

rtdef.h

/*
*************************************************************************
*                               错误码定义
*************************************************************************
*/
/* RT-Thread 错误码重定义 */
#define RT_EOK                          0               /* 没有错误 */
#define RT_ERROR                        1               /* 一个常规错误 */
#define RT_ETIMEOUT                     2               /* 超时 */
#define RT_EFULL                        3               /* 资源已满 */
#define RT_EEMPTY                       4               /* 资源为空 */
#define RT_ENOMEM                       5               /* 没有内存 */
#define RT_ENOSYS                       6               /* No system */
#define RT_EBUSY                        7               /* 忙*/
#define RT_EIO                          8               /* IO错误 */
#define RT_EINTR                        9               /* 中断系统调用 */
#define RT_EINVAL                       10              /* 无效形参 */

线程状态定义

/*
 * 线程状态定义
 */
#define RT_THREAD_INIT                  0x00                /* 初始态 */
#define RT_THREAD_READY                 0x01                /* 就绪态 */
#define RT_THREAD_SUSPEND               0x02                /* 挂起态 */
#define RT_THREAD_RUNNING               0x03                /* 运行态 */
#define RT_THREAD_BLOCK                 RT_THREAD_SUSPEND   /* 阻塞态 */
#define RT_THREAD_CLOSE                 0x04                /* 关闭态 */
#define RT_THREAD_STAT_MASK             0x0f

#define RT_THREAD_STAT_SIGNAL           0x10
#define RT_THREAD_STAT_SIGNAL_READY     (RT_THREAD_STAT_SIGNAL | RT_THREAD_READY)
#define RT_THREAD_STAT_SIGNAL_SUSPEND   0x20
#define RT_THREAD_STAT_SIGNAL_MASK      0xf0

线程初始化函数

优先级、错误码、状态

rt_err_t 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)
{
	/* 线程对象初始化 */
	/* 线程结构体开头部分的成员就是rt_object_t类型 */
	rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
    rt_list_init(&(thread->tlist));
	
	thread->entry = (void *)entry;
	thread->parameter = parameter;

	thread->stack_addr = stack_start;
	thread->stack_size = stack_size;
	
	/* 初始化线程栈,并返回线程栈指针 */
	thread->sp = (void *)rt_hw_stack_init( thread->entry, 
		                                   thread->parameter,
							               (void *)((char *)thread->stack_addr + thread->stack_size - 4) );
	
    thread->init_priority    = priority;
    thread->current_priority = priority;
    thread->number_mask = 0;
    
    /* 错误码和状态 */
    thread->error = RT_EOK;
    thread->stat  = RT_THREAD_INIT;
    
    return RT_EOK;
}

调度器初始化函数

/* 初始化系统调度器 */
void rt_system_scheduler_init(void)
{	
    register rt_base_t offset;	
	
	/* 线程优先级表初始化 */
	for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
	{
			rt_list_init(&rt_thread_priority_table[offset]);
	}
    
	/* 初始化当前优先级为空闲线程的优先级 */
    rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
    
	/* 初始化当前线程控制块指针 */
	rt_current_thread = RT_NULL;
    
    /* 初始化线程就绪优先级组 */
    rt_thread_ready_priority_group = 0;
}

线程启动函数

/**
 * 启动一个线程并将其放到系统的就绪列表中
 * 
 * @param thread 待启动的线程
 *
 * @return 操作状态, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_startup(rt_thread_t thread)
{
    /* 设置当前优先级为初始优先级 */
    thread->current_priority = thread->init_priority;
    thread->number_mask = 1L << thread->current_priority;    
    
    /* 改变线程的状态为挂起状态 */
    thread->stat = RT_THREAD_SUSPEND;    
    /* 然后恢复线程 */
    rt_thread_resume(thread);
    
    if (rt_thread_self() != RT_NULL)
    {
        /* 系统调度 */
        rt_schedule();
    }

    return RT_EOK;
}

rt_thread_t rt_thread_self(void)
{
    return rt_current_thread;
}
/**
 * 该函数用于恢复一个线程然后将其放到就绪列表
 *
 * @param thread 需要被恢复的线程
 *
 * @return 操作状态, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_resume(rt_thread_t thread)
{
    register rt_base_t temp;
    
    /* 将被恢复的线程必须在挂起态,否则返回错误码 */
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
    {
        return -RT_ERROR;
    }

    /* 关中断 */
    temp = rt_hw_interrupt_disable();

    /* 从挂起队列移除 */
    rt_list_remove(&(thread->tlist));

    /* 开中断 */
    rt_hw_interrupt_enable(temp);

    /* 插入就绪列表 */
    rt_schedule_insert_thread(thread);

    return RT_EOK;
}

空闲中断初始化函数

/**
 * @ingroup SystemInit
 *
 * 初始化空闲线程,启动空闲线程
 *
 * @note 当系统初始化的时候该函数必须被调用
 */
void rt_thread_idle_init(void)
{
    
    /* 初始化线程 */
    rt_thread_init(&idle,
                   "idle",
                   rt_thread_idle_entry,
                   RT_NULL,
                   &rt_thread_stack[0],
                   sizeof(rt_thread_stack),
                   RT_THREAD_PRIORITY_MAX-1);
    
	/* 启动线程 */
    rt_thread_startup(&idle);
}

启动系统调度器

/* 启动系统调度器 */
void rt_system_scheduler_start(void)
{
    register struct rt_thread *to_thread;
    register rt_ubase_t highest_ready_priority;
                              
    /* 获取就绪的最高优先级 */
    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
                              
    /* 获取将要运行线程的线程控制块 */
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    rt_current_thread = to_thread;

    /* 切换到新的线程 */
    rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

    /* 永远不会返回 */                                                      
}

调度函数

void rt_schedule(void)
{
    rt_base_t level;
    register rt_ubase_t highest_ready_priority;
    struct rt_thread *to_thread;
    struct rt_thread *from_thread;

    /* 关中断 */
    level = rt_hw_interrupt_disable();

    /* 获取就绪的最高优先级 */
    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
    /* 获取就绪的最高优先级对应的线程控制块 */
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    /* 如果目标线程不是当前线程,则要进行线程切换 */
    if (to_thread != rt_current_thread)
    {
        rt_current_priority = (rt_uint8_t)highest_ready_priority;
        from_thread         = rt_current_thread;
        rt_current_thread   = to_thread;

        rt_hw_context_switch((rt_uint32_t)&from_thread->sp,
                             (rt_uint32_t)&to_thread->sp);
        
        /* 开中断 */
        rt_hw_interrupt_enable(level);

    }
    else 
    {
        /* 开中断 */
        rt_hw_interrupt_enable(level);
    }
}

阻塞延时函数

void rt_thread_delay(rt_tick_t tick)
{
    register rt_base_t temp;
    struct rt_thread *thread;
    
	/* 失能中断 */
    temp = rt_hw_interrupt_disable();
    
    thread = rt_current_thread;
    thread->remaining_tick = tick;
    
    /* 改变线程状态 */
    thread->stat = RT_THREAD_SUSPEND;
    rt_thread_ready_priority_group &= ~thread->number_mask;

    /* 使能中断 */
    rt_hw_interrupt_enable(temp);
    
	/* 进行系统调度 */
	rt_schedule();
}

时基更新函数

void rt_tick_increase(void)
{
    rt_ubase_t i;
    struct rt_thread *thread;
    rt_tick ++;
    
    /* 扫描就绪列表中所有线程的remaining_tick,如果不为0,则减1 */
	for(i=0; i<RT_THREAD_PRIORITY_MAX; i++)
	{
        thread = rt_list_entry( rt_thread_priority_table[i].next,
								 struct rt_thread,
							     tlist);
		if(thread->remaining_tick > 0)
		{
			thread->remaining_tick --;
            if(thread->remaining_tick == 0)
            {
                //rt_schedule_insert_thread(thread);
                rt_thread_ready_priority_group |= thread->number_mask;
            }
		}
	} 
    /* 任务调度 */
	rt_schedule();
}

main函数

/* 初始化线程 */
rt_thread_init( &rt_flag1_thread,                 /* 线程控制块 */
               "rt_flag1_thread",                /* 线程名字,字符串形式 */
               flag1_thread_entry,               /* 线程入口地址 */
               RT_NULL,                          /* 线程形参 */
               &rt_flag1_thread_stack[0],        /* 线程栈起始地址 */
               sizeof(rt_flag1_thread_stack),    /* 线程栈大小,单位为字节 */
               2);                               /* 优先级 */
/* 将线程插入到就绪列表 */
//rt_list_insert_before( &(rt_thread_priority_table[0]),&(rt_flag1_thread.tlist) );
rt_thread_startup(&rt_flag1_thread);

/* 初始化线程 */
rt_thread_init( &rt_flag2_thread,                 /* 线程控制块 */
               "rt_flag2_thread",                /* 线程名字,字符串形式 */
               flag2_thread_entry,               /* 线程入口地址 */
               RT_NULL,                          /* 线程形参 */
               &rt_flag2_thread_stack[0],        /* 线程栈起始地址 */
               sizeof(rt_flag2_thread_stack),    /* 线程栈大小,单位为字节 */
               3);                               /* 优先级 */
/* 将线程插入到就绪列表 */
//rt_list_insert_before( &(rt_thread_priority_table[1]),&(rt_flag2_thread.tlist) );
rt_thread_startup(&rt_flag2_thread);
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值