RT-Thread线程的调度机理

RT-Thread线程的调度机理
1.何时切换线程?先引用一张官网给出的“线程状态切换图”
线程状态切换图
图1 线程状态切换图
1.1启动线程
线程初始化时,默认被设置为初始状态。线程启动后(调用rt_thread_startup),先将线程设置为挂起态,然后恢复到就绪态(调用rt_thread_resume),紧接着执行线程调度。
1.2发生阻塞(线程挂起)
1.2.1延时。若正在运行态的线程无需任何通信或同步,它就有必要通过延时来让出CPU的控制权,否则比它低的线程将无法获得运行的机会。延时,就是让线程在可以接受的时间段休息一会儿(主动让出CPU控制权),具体的延时时间要根据实际情况来设计,在此不详述。
1.2.2等待线程通信或同步信号(信号量、互斥量、事件标志、接收邮箱、接收消息队列、内存池的分配)。往往,线程需要获取某些信号用来同步线程或者响应用户操作、执行某种请求等,为此,如果要获取的信号已经到来则立即执行接下来的程序,反之,就要先让出CPU的控制权,启动任务切换。
1.2.3由于特别需要,对某就绪态的线程挂起。比如,线程A在运行时,需要获取线程C的信号量,而此时,就绪表有更高优先级的线程B,但是线程B又要获取线程A接下来要发送的消息邮箱信息,这样正常的执行顺序是A->B->C->A->B.显然,我们可优化一下,在执行线程A未获取信号量时将线程B挂起,线程C取得了CPU控制权得到执行后线程A接着执行,在线程得到信号量后将线程B恢复,这样线程B得到CPU的控制权,即下图1.2.3.2的执行顺序A->C->A->B.
在这里插入图片描述
图1.2.3.1 线程就绪表
在这里插入图片描述
图1.2.3.2 优先级反转
1.3中断
中断服务函数可以发送信号量、互斥量、事件标志、消息邮箱、消息队列信号,使得等待消息的线程进入就绪状态。同时在中断服务函数执行完成后,也可以进行任务调度。
1.4定时器运行时间
1.4.1同一优先级线程的时间片耗尽,这时如果当前同一优先级的线程处于就绪态(并且没有更高优先级线程处于就绪态),就把此就绪态线程切换至运行态,否则切换到就绪表其它较高优先级线程。
1.4.2线程通信或同步信号(信号量、互斥量、事件标志、接收邮箱、接收消息队列、内存池的分配)的等待超时,要求将此线程插入线程就绪表,若此线程为就绪表优先级最高,将于下次线程切换时取得CPU运行控制权。
1.5进入空闲线程
2.线程的调度
2.1查找就绪表中最高优先级的线程(_get_highest_priority_thread)
2.1.1根据全局变量rt_thread_ready_priority_group(当最大优先级值为32)或rt_thread_ready_table找出就绪表中优先级最高的线程优先级编号。
2.1.2当全局变量rt_thread_ready_priority_group的某一位为1,意味着此位的位编号对应一个(组)线程优先级,若某位为1,意味着此位对应的优先级ID的线程(组)之一进入就绪态。
2.1.3线程优先级ID号越小优先级越高,因此查找就绪表中最高优先级ID号只要查找到rt_thread_ready_priority_group或rt_thread_ready_table[]中位编号最小为1的位,即为最高优先级线程(组)。
2.1.4以空间换时间使用bitmap数组查找就绪表最高优先级的线程优先级编号,bitmap数组有256个元素,即一个字节所能表征的所有数据,这里假设group低8位为102,查表bitmap[102]=1可知,就绪表中优先级就高的线程的优先级为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
};
2.1.5从就绪表中取出最高优先级线程控制块指针——就绪态的线程控制块的.tlist成员挂接在优先级编号对应的rt_thread_ready_table[优先级编号]成员链表当中。根据.tlist成员在线程控制块的位置,可计算得出线程控制块的地址。
在这里插入图片描述
图2.1.5 取出就绪表中最高优先级线程
2.2将切换到运行态的线程从就绪表中删除(rt_schedule_remove_thread)
2.2.1从就绪表中将最高优级线程的.tlist成员从链表中删除。
在这里插入图片描述
图2.2.1 删除就绪表中最高优先级线程
2.2.2判断就绪表原最高优先级编号的成员链表是否为空——经过2.2.1操作,若此链表为空,意味着此刻没有相同优先级线程就绪,否则有同优先级线程就绪,需要根据时间片剩余时间确认在下一次调度时是否有机会进入运行态。
2.2.3将原最高优先级编号对应rt_thread_ready_priority_group的位,依据2.2.2的判断进行位清除操作。

2.3将从运行态转到就绪态的线程插入就绪表(rt_schedule_insert_thread(from_thread))
2.3.1将从运行态转到就绪态的线程的状态更改为就绪态。
2.3.2将从运行态转到就绪态的线程插入就绪表对应优先级编号链表的尾部。
在这里插入图片描述
图2.3.2 把线程D插入就绪表
2.3.3将当前线程优先级编号对应rt_thread_ready_priority_group的位进行位置位操作。
2.4线程临界区切换(rt_hw_context_switch(&from_thread->sp, &to_thread->sp))
2.4.1从运行态切换至非运行态的线程栈指针from_thread->sp,线程栈被压入CPU的寄存器,from_thread->sp指向压栈后最新的地址。
在这里插入图片描述
图2.4.1 从运行态切换至非运行态的线程栈被压入CPU的寄存器
2.4.2从非运行态切换至运行态的线程栈指针to_thread->sp,需要将栈当中的数据弹出到CPU寄存器,以恢复到上次打断的位置继续运行。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值