RT-Thread的优先级算法
2011-06-10 15:45
197 查看
RT-Thread的优先级有3种级别,最大分别是8,32,256.我们逐一来分析,在此之前看一下下面的变量:
const rt_uint8_t rt_lowest_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
};
/* 任务优先级的链表—不同优先级有不同的链表(为了同优先级时间片轮) */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
…
#if RT_THREAD_PRIORITY_MAX > 32
/* maximun priority level, 256 */
rt_uint32_t rt_thread_ready_priority_group; /* 任务优先级组 */
rt_uint8_t rt_thread_ready_table[32]; /* 任务就绪表 */
#else
/* maximun priority level, 32 */
rt_uint32_t rt_thread_ready_priority_group;
#endif
一,初始化 -- rt_system_scheduler_init()
这一步初始化了rt_thread_priority_table,rt_thread_ready_priority_group。这里注意最大优先级是8,32的不初始化rt_thread_ready_table。
二,任务建立 -- rt_application_init()
这里建立一个任务rt_thread_create(),并rt_thread_startup。这里要区分一下:
1, RT_THREAD_PRIORITY_MAX > 32 :这种情况下
thread->number = thread->current_priority >> 3; /* 5bit */ thread->number_mask = 1L << thread->number;
thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
这里我们可以看出,他把任务的高5位作为行号(2^5 = 32),低3位作为列号(2^3 = 8)。
2, RT_THREAD_PRIORITY_MAX <=32
thread->number_mask = 1L << thread->current_priority;
因为一个4字节的数有32位,所以这里用32位的数的每个bit位来表示对应的优先级。
紧接着调用rt_thread_resume(),在里面调用rt_schedule_insert_thread(thread),这这里首先会把任务的链表插入到对应优先级的链表rt_thread_priority_table里,接着如果RT_THREAD_PRIORITY_MAX > 32,那么还会执行:
rt_thread_ready_table[thread->number] |= thread->high_mask;
把任务的列号与到任务就绪表对应的那一行。紧接着:
rt_thread_ready_priority_group |= thread->number_mask;
这里就把任务的行号放到任务就绪表组里面。
三,调度器启动 -- rt_system_scheduler_start()
1, RT_THREAD_PRIORITY_MAX == 8 :
highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];
这里根据任务就绪表组反推算出最高优先级。
2, RT_THREAD_PRIORITY_MAX != 8 :
register rt_ubase_t number;
/* find out the highest priority task */
if (rt_thread_ready_priority_group & 0xff)
{number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];}
else if (rt_thread_ready_priority_group & 0xff00)
{number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;}
else if (rt_thread_ready_priority_group & 0xff0000)
{number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;}
else
{number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;}
这段代码我们可以计算出优先级对应的行号。
a) RT_THREAD_PRIORITY_MAX == 32
highest_ready_priority = number;
因为这种模式下面没有rt_thread_ready_table,也就是说每一个组里面只有一个任务,最高优先级就可以直接算出来。
b) RT_THREAD_PRIORITY_MAX == 256
这种模式有rt_thread_ready_table,也就是说每一个行里面需要有8个列号对应,highest_ready_priority = (number << 3) + rt_lowest_bitmap[rt_thread_ready_table[number]];这里的优先级是由行号与列号共同组合而成的。
四,任务从就绪态切换到其他形态 -- rt_sem_take()或者其他此类能够让任务进入挂起态的函数。
rt_sem_take()->rt_ipc_object_suspend()->rt_thread_suspend()->rt_schedule_remove_thread(),这里就是真正进行任务就绪态转换其他形态的地方。首先rt_list_remove(&(thread->tlist));把任务的链表从就绪链表里面删除。然后判断当前优先级的链表组是否为空(事件片轮的调度),为空就需要把任务从就绪表里面删除。
/* remove thread from ready list */
rt_list_remove(&(thread->tlist));
if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
{
#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] &= ~thread->high_mask;
if (rt_thread_ready_table[thread->number] == 0)
{
rt_thread_ready_priority_group &= ~thread->number_mask;
}
#else
rt_thread_ready_priority_group &= ~thread->number_mask;
#endif
}
至此,基本上的原理分析就明了了。对RT-Thread的内核又深入了解了一步。
const rt_uint8_t rt_lowest_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
};
/* 任务优先级的链表—不同优先级有不同的链表(为了同优先级时间片轮) */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
…
#if RT_THREAD_PRIORITY_MAX > 32
/* maximun priority level, 256 */
rt_uint32_t rt_thread_ready_priority_group; /* 任务优先级组 */
rt_uint8_t rt_thread_ready_table[32]; /* 任务就绪表 */
#else
/* maximun priority level, 32 */
rt_uint32_t rt_thread_ready_priority_group;
#endif
一,初始化 -- rt_system_scheduler_init()
这一步初始化了rt_thread_priority_table,rt_thread_ready_priority_group。这里注意最大优先级是8,32的不初始化rt_thread_ready_table。
二,任务建立 -- rt_application_init()
这里建立一个任务rt_thread_create(),并rt_thread_startup。这里要区分一下:
1, RT_THREAD_PRIORITY_MAX > 32 :这种情况下
thread->number = thread->current_priority >> 3; /* 5bit */ thread->number_mask = 1L << thread->number;
thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
这里我们可以看出,他把任务的高5位作为行号(2^5 = 32),低3位作为列号(2^3 = 8)。
2, RT_THREAD_PRIORITY_MAX <=32
thread->number_mask = 1L << thread->current_priority;
因为一个4字节的数有32位,所以这里用32位的数的每个bit位来表示对应的优先级。
紧接着调用rt_thread_resume(),在里面调用rt_schedule_insert_thread(thread),这这里首先会把任务的链表插入到对应优先级的链表rt_thread_priority_table里,接着如果RT_THREAD_PRIORITY_MAX > 32,那么还会执行:
rt_thread_ready_table[thread->number] |= thread->high_mask;
把任务的列号与到任务就绪表对应的那一行。紧接着:
rt_thread_ready_priority_group |= thread->number_mask;
这里就把任务的行号放到任务就绪表组里面。
三,调度器启动 -- rt_system_scheduler_start()
1, RT_THREAD_PRIORITY_MAX == 8 :
highest_ready_priority = rt_lowest_bitmap[rt_thread_ready_priority_group];
这里根据任务就绪表组反推算出最高优先级。
2, RT_THREAD_PRIORITY_MAX != 8 :
register rt_ubase_t number;
/* find out the highest priority task */
if (rt_thread_ready_priority_group & 0xff)
{number = rt_lowest_bitmap[rt_thread_ready_priority_group & 0xff];}
else if (rt_thread_ready_priority_group & 0xff00)
{number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 8) & 0xff] + 8;}
else if (rt_thread_ready_priority_group & 0xff0000)
{number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 16) & 0xff] + 16;}
else
{number = rt_lowest_bitmap[(rt_thread_ready_priority_group >> 24) & 0xff] + 24;}
这段代码我们可以计算出优先级对应的行号。
a) RT_THREAD_PRIORITY_MAX == 32
highest_ready_priority = number;
因为这种模式下面没有rt_thread_ready_table,也就是说每一个组里面只有一个任务,最高优先级就可以直接算出来。
b) RT_THREAD_PRIORITY_MAX == 256
这种模式有rt_thread_ready_table,也就是说每一个行里面需要有8个列号对应,highest_ready_priority = (number << 3) + rt_lowest_bitmap[rt_thread_ready_table[number]];这里的优先级是由行号与列号共同组合而成的。
四,任务从就绪态切换到其他形态 -- rt_sem_take()或者其他此类能够让任务进入挂起态的函数。
rt_sem_take()->rt_ipc_object_suspend()->rt_thread_suspend()->rt_schedule_remove_thread(),这里就是真正进行任务就绪态转换其他形态的地方。首先rt_list_remove(&(thread->tlist));把任务的链表从就绪链表里面删除。然后判断当前优先级的链表组是否为空(事件片轮的调度),为空就需要把任务从就绪表里面删除。
/* remove thread from ready list */
rt_list_remove(&(thread->tlist));
if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
{
#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] &= ~thread->high_mask;
if (rt_thread_ready_table[thread->number] == 0)
{
rt_thread_ready_priority_group &= ~thread->number_mask;
}
#else
rt_thread_ready_priority_group &= ~thread->number_mask;
#endif
}
至此,基本上的原理分析就明了了。对RT-Thread的内核又深入了解了一步。
相关文章推荐
- rt-thread线程调度器获取当前最高优先级线程算法过程分析
- rt-thread线程调度器获取当前最高优先级线程算法过程分析
- 优先级反转实验,使用信号量实现【RT-Thread学习笔记 5】
- rt-thread的位图调度算法分析
- 优先级反转实验,使用信号量实现【RT-Thread学习笔记 5】
- rt-thread的位图调度算法分析
- rt-thread的位图调度算法分析
- rt-thread的小内存管理算法分析
- rt-thread的位图调度算法分析
- RT-thread内核之小内存管理算法
- rt-thread的小内存管理算法分析
- 【RT-Thread学习笔记 3】线程优先级抢占实验
- 线程优先级抢占实验【RT-Thread学习笔记 3】
- RT-Thread相同优先级线程的调度
- 【RT-Thread学习笔记 5】优先级反转实验,使用信号量实现
- RT-thread内核之小内存管理算法
- 线程优先级抢占实验【RT-Thread学习笔记 3】
- RT-thread内核之线程调度器
- 操作系统进程调度算法 先到先服务 短作业 优先级 时间片轮转
- STM32 + RT Thread OS 学习笔记[四]