空闲线程及其钩子函数
一个良好的程序中,线程都是由事件驱动的,平时大部分事件都处于挂起状态。当我们自己创建的线程都无法执行时,调度器需要找到一个可以运行的线程,所以要提供空闲线程:空闲线程的优先级最低,他不能阻碍用户线程运行,空闲线程要么处于就绪态,要么处于运行态,永远不会被挂起。
钩子函数:钩子函数可以挂载在一些系统模块中,用于对各个模块的信息进行监听, 截取一些系统内的信息,进行处理或者转发。注意钩子函数不是用户自己触发的,而是绑定在系统模块中,当该模块被执行时会触发钩子函数。
我们可以添加一个空闲线程的钩子函数,空闲线程的循环每执行一次,就会调用一次钩子函数。钩子函数的作用有这些:
- 执行一些低优先级的、后台的、需要连续执行的函数
- 测量系统的空闲时间:空闲线程能被执行就意味着所有的高优先级线程都停止了,所以测量空闲线程占据的时间,就可以算出处理器占用率。(rtt中finsh中可以显示线程的占用率)
- 让系统进入省电模式:空闲线程能被执行就意味着没有重要的事情要做,当然可以进入省电模式了。
空闲线程的钩子函数的限制:
- 不能导致空闲线程进入挂起状态、关闭状态
- 不能使使用 rt_thread_delay()等可能会导致线程挂起的函数
- malloc()、free()等内存相关的函数,内部使用了信号量作为临界区保护,也不允许在钩子函数中使用
在src\ idle.c中可以找到创建空闲线程的代码:
void rt_thread_idle_init(void)
{
/* initialize thread */
rt_thread_init(&idle,
"tidle",
rt_thread_idle_entry,
RT_NULL,
&rt_thread_stack[0],
sizeof(rt_thread_stack),
RT_THREAD_PRIORITY_MAX - 1,
32);
/* startup */
rt_thread_startup(&idle);
}
空闲线程的入口函数如下:
用户可以提供多个钩子函数:idle_hook_list[i],如果提供了就会被调用
rt_thread_idle_excute用来清理线程
static void rt_thread_idle_entry(void *parameter)
{
while (1)
{
#ifdef RT_USING_IDLE_HOOK
rt_size_t i;
for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] != RT_NULL)
{
idle_hook_list[i]();
}
}
#endif
rt_thread_idle_excute();
#ifdef RT_USING_PM
rt_system_power_manager();
#endif
}
}
为空闲线程添加钩子函数t_thread_idle_sethook,传入钩子函数入口,该函数会将钩子函数添加进idle_hook_list:
rt_err_t rt_thread_idle_sethook(void (*hook)(void))
{
rt_size_t i;
rt_base_t level;
rt_err_t ret = -RT_EFULL;
/* disable interrupt */
level = rt_hw_interrupt_disable();
for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] == RT_NULL)
{
idle_hook_list[i] = hook;
ret = RT_EOK;
break;
}
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
return ret;
}
对应的删除钩子函数使用rt_thread_idle_dehook