调度
RT-Thread 的调度算法为基于优先级调度和基于时间片轮转调度共存的策略。系统中可能有多个线程,它们的优先级可能相同、可能不同,RT-Thread 采用的调度策略是:可抢占:高优先级的就绪线程会“立刻”抢占低优先级的线程;时间片轮转:同优先级别的就绪线程,依次运行
在rtt运行中,会不断的切换线程,这由rt_schedule()来实现。在调度器中我们可以绑定一个钩子函数,用于我们查看调度情况
rt_schedule()的部分代码如下:
void rt_schedule(void)
{
rt_base_t level;
struct rt_thread *to_thread;
struct rt_thread *from_thread;
/* disable interrupt */
level = rt_hw_interrupt_disable();
/* check the scheduler is enabled or not */
if (rt_scheduler_lock_nest == 0)
{
register rt_ubase_t highest_ready_priority;
#if RT_THREAD_PRIORITY_MAX <= 32
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#else
register rt_ubase_t number;
number = __rt_ffs(rt_thread_ready_priority_group) - 1;
highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#endif
/* get switch to thread */
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
struct rt_thread,
tlist);
/* if the destination thread is not the same as current thread */
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_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));
.............................................................
.............................................................
在这段代码的最后一行 RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));,就是调度器触发钩子函数的入口,可以看看该宏的实现:
#define RT_OBJECT_HOOK_CALL(func, argv) \
do { if ((func) != RT_NULL) func argv; } while (0)
将该宏展开就是:
do
{
if(rt_scheduler_hook != RT_NULL)
rt_scheduler_hook(from_thread, to_thread);
}while(0)
现在我们只需要编写rt_scheduler_hook函数,就可以让调度器进去我们的钩子函数,在rtt中提供了一个API:rt_scheduler_sethook,该函数的实现是:
rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to))
{
rt_scheduler_hook = hook;
}
这个函数非常简单,就是将我们传进去的函数入口当作rt_scheduler_hook,是调度器执行时进入我们的钩子函数,在调度器的钩子函数中有两个参数from_thread和to_thread,前者是调度时上一个线程的名称,后者时调度时下一个线程的名称。所以我们可以用该钩子函数查看调度的上下文
//在main函数中绑定钩子函数
rt_scheduler_sethook(hook_of_scheduler);
//自己编写的钩子函数
static void hook_of_scheduler(struct rt_thread* from, struct rt_thread* to)
{
rt_kprintf("Thread:%s --> Thread:%s \r\n", from->name, to->name);
}
//打印结果
Thread:led1 --> Thread:tidle
Thread:tidle --> Thread:led
//