3 线程调度scheduler
rtthread中对于多线程切换是通过优先级表搭配优先级组进行调度的,优先级表中存储所有线程的node,优先级组中存储线程的优先级;
优先级表通常有32个对象,每个优先级都是一个list_head节点,相同优先级的线程存储在相同优先级链表下;
rtos中高优先级的线程可以将低优先级的线程suspend,然后让芯片执行高优先级的线程;对于优先级相同的线程rtos通过时间片轮询执行;
线程调度函数比想象中简单的多,主要分为两个函数,一个是第一次执行调度的函数、一个是之后执行调度的函数;
3.1 rt_thread_ready_priority_group
线程就绪优先级组是一个32bits常数,每1bit对应一个优先级,通过对优先级组中最低位的判断可以知道当前线程的最高优先级;
优先级组用来配合优先级表进行系统调度;
3.1.1 优先级组定义
//scheduler.c
#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
3.1.2 优先级组查询
如果对优先级组按bit判断取出最高优先级,rtthread觉得那样浪费时间,所以rtthread采用了一种以内存换效率的数组寻址优先级,搭配逻辑判断使用;
为什么不32bit全部采用数组寻址,可能全部采用数组寻址内存占用又太大划不来;
//scheduler.c 优先级组调用方式;
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);
//kservice.c
//判断函数中对优先级都进行了+1处理,所以调用函数中又-1处理;
int __rt_ffs(int value)
{
if (value == 0)
return 0; //优先级组为空,调用函数中-1处理得到-1 error;
if (value & 0xff)
return __lowest_bit_bitmap[value & 0xff] + 1; //bit[7:0],优先级为0也会+1处理;
if (value & 0xff00)
return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9; //bit[15:8]
if (value & 0xff0000)
return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17; //bit[23:16]
return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25; //bit[31:24]
}
//咋一看还以为是什么复杂的东西,其实这个数组纯粹力气活,把可能性(0:255)依次穷举列出,然后再把该数值的最高优先级存入在数值所在位;
//不要觉得这个数组是个力气活就不当回事,人家还有一个高精尖的名字叫“位图算法”;
//下面的优先级是所在字节的实际优先级
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,

RTThread操作系统使用优先级表和优先级组进行线程调度。优先级表包含32个对象,每个对象对应一个优先级链表。高优先级线程可以暂停低优先级线程,同优先级线程通过时间片轮询执行。调度主要由rt_thread_ready_priority_group和rt_thread_priority_table管理,通过位图算法快速找到最高优先级线程。系统初始化时会设置这些数据结构,调度过程包括插入和删除线程,实际调度由rt_schedule函数执行。

1354

被折叠的 条评论
为什么被折叠?



